`
wangwei3
  • 浏览: 118100 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

JavaScript内核之基本概念

 
阅读更多
本章主要讲述JavaScript中的数据类型(基本类型与引用类型),变量(包括变量的作用域),操作符(主要是一些较为常见,但是不容易从字面上理解的操作符)。由于JavaScript中的“一切皆对象”,在掌握了这些基本的概念之后,读者就可以较为轻松的理解诸如作用域,调用对象,闭包,currying等等较难理解的概念了。

数据类型

有程序设计经验的读者肯定知道,在C或者Java这样的语言中,数据是有类型的,比如用以表示用户名的属性是字符串,而一个雇员的年龄则是一个数字,表示UI上的一个开关按钮的数据模型则为布尔值等等,对数字可能还可以细分为浮点数,整型数,整型数又可能分为长整型和短整型,总而言之,它们都表示语言中的数据的值的类型。

JavaScript中的数据类型分为两种:基本数据类型和对象类型,其中对象类型包含对象,数组,以及函数(事实上,函数,数组等也都是对象,这个在后边的章节详述)。

1.1.1 基本数据类型

在JavaScript中,包含三种基本的数据类型,字符串(String),数值(Number),布尔值(boolean),下面是一些简单的例子:

<strong>
var str = "Hello, world";//字符串 
var i = 10;//整型数 
var f = 2.3;//浮点数    
var b = true;//布尔值</strong>

我们可以分别查看变量的值及变量的类型:

print(str);  
print(i);  
print(f);  
print(b);     
print(typeof str);  
print(typeof i); 
print(typeof f);  
print(typeof b);


注意,在此处使用的print()函数为rhino解释器的顶层对象的方法,可以用来打印字符串,通常情况下,在客户端,程序员多使用alert()进行类似的动作,alert()是浏览器中JavaScript解释器的顶层对象(window)的一个方法。

Hello, world  
10  
2.3  
true    
string  
number  
number  
Boolean 


在JavaScript中,所有的数字,不论是整型浮点,都属于“数字”基本类型。typeof是一个一元的操作符,在本章的另外一个小节会专门讲到。

1.1.2 对象类型

这里提到的对象不是对象本身,而是指一种类型,我们在第三章会对对象进行详细的讨论,此处的对象包括,对象(属性的集合,即键值的散列表),数组(有序的列表),函数(包含可执行的代码)。

对象类型是一种复合的数据类型,其基本元素由基本数据类型组成,当然不限于基本类型,比如对象类型中的值可以是其他的对象类型实例,我们通过例子来说明:

var str = "Hello, world";  
var obj = new Object();  
obj.str = str;  
obj.num = 2.3;     
var array = new Array("foo", "bar", "zoo");     
var func = function(){      
print("I am a function here");  
}


可以看到,对象具有属性,如obj.str, obj.num,这些属性的值可以是基本类型,事实上还可以更复杂,我们来看看他们的类型:

print(typeof obj);  
print(typeof array);  
print(typeof func);     
//将打印出  
object  
object  
function 


读者可能会对print(typeof array)打印出object感到奇怪,事实上,对象和数组的界限并不那么明显(事实上它们是属于同一类型的),但是他们的行为却非常不同,本书的后续章节将两个重要的数据类型做了分别介绍。

2.1.3 两者之间的转换

类似与Java中基本数据类型的自动装箱拆箱,JavaScript也有类似的动作,基本数据类型在做一些运算时,会临时包装一个对象,做完运算后,又自动释放该对象。我们可以通过几个例子来说明:

var str = "JavaScript Kernal";  
print(str.length);
//打印17


str为一个字符串,通过typeof运算符可知其type为”string”,而:

var str2 = new String("JavaScript Kernal");  
print(typeof str2);


可知,str2的type为”object”,即这两者并不相同,那么为什么可以使用str.length来的到str的长度呢?事实上,当使用str.length时,JavaScript会自动包装一个临时的String对象,内容为str的内容,然后获取该对象的length属性,最后,这个临时的对象将被释放。

而将对象转换为基本类型则是通过这样的方式:通过调用对象的valueOf()方法来取得对象的值,如果和上下文的类型匹配,则使用该值。如果valueOf取不到值的话,则需要调用对象的toString()方法,而如果上下文为数值型,则又需要将此字符串转换为数值。由于JavaScript是弱类型的,所以JavaScript引擎需要根据上下文来“猜测”对象的类型,这就使得JavaScript的效率比编译型的语言要差一些。

valueOf()的作用是,将一个对象的值转换成一种合乎上下文需求的基本类型,toString()则名副其实,可以打印出对象对应的字符串,当然前提是你已经“重载”了Object的toString()方法。

事实上,这种转换规则会导致很多的问题,比如,所有的非空对象,在布尔值环境下,都会被转成true,比如:

function convertTest(){  
if(new Boolean(false) && new Object() &&   new String("") && new Array()){         
print("convert to boolean")      
}    
}     
convertTest();//convert to Boolean


初学者容易被JavaScript中的类型转换规则搞晕掉,很多情况下会觉得那种写法看着非常别扭,其实只需要掌握了规则,这些古怪的写法会大大的提高代码的性能,我们通过例子来学习这些规则:

var x = 3;  
var y = x + "2";// => 32  
var z = x + 2;// => 5     
print(y);  
print(z); 


通常可以在JS代码中发现这样的代码:

if(datamodel.item){      
//do something...  
}else{      
datamodel.item = new Item();  
}


这种写法事实上具有更深层次的含义:

应该注意到,datamodel.item是一个对象(字符串,数字等),而if需要一个boolean型的表达式,所以这里进行了类型转换。在JavaScript中,如果上下文需要boolean型的值,则引擎会自动将对象转换为boolean类型。转换规则为,如果该对象非空,则转换为true,否则为false.因此我们可以采取这种简写的形式。

而在传统的编程语言(强类型)中,我们则需要:

if(datamodel.item != null){      
//do something...  
}else{      
datamodel.item = new Item();  
}


2.1.4类型的判断

前面讲到JavaScript特性的时候,我们说过,JavaScript是一个弱类型的语言,但是有时我们需要知道变量在运行时的类型,比如,一个函数的参数预期为另一个函数:

function handleMessage(message, handle){      
return handle(message);  
}

当调用handleMessage的函数传递的handle不是一个函数则JavaScript引擎会报错,因此我们有必要在调用之前进行判断:

function handleMessage(message, handle){      
if(typeof handle == "function"){         
return handle(message);       
}else{         
throw new Error("the 2nd argument should be a function");      
}  
}


但是,typeof并不总是有效的,比如下面这种情况:

var obj = {};  
var array = ["one", "two", "three", "four"];     
print(typeof obj);//object  
print(typeof array); //object


运行结果显示,对象obj和数组array的typeof值均为”object”,这样我们就无法准确判断了,这时候,可以通过调用instanceof来进行进一步的判断:

print(obj instanceof Array);//false  
print(array instanceof Array);//true 

第一行代码返回false,第二行则返回true。因此,我们可以将typeof操作符和instanceof操作符结合起来进行判断。

2.2 变量

变量,即通过一个名字将一个值关联起来,以后通过变量就可以引用到该值,比如:

var str = "Hello, World";  
var num = 2.345;

当我们下一次要引用”Hello, Wrold”这个串进行某项操作时,我们只需要使用变量str即可,同样,我们可以用10*num来表示10*2.345。变量的作用就是将值“存储”在这个变量上。

2.2.1基本类型和引用类型

在上一小节,我们介绍了JavaScript中的数据类型,其中基本类型如数字,布尔值,它们在内存中都有固定的大小,我们通过变量来直接访问基本类型的数据。而对于引用类型,如对象,数组和函数,由于它们的大小在原则上是不受任何限制的,故我们通过对其引用的访问来访问它们本身,引用本身是一个地址,即指向真实存储复杂对象的位置。

基本类型和引用类型的区别是比较明显的,我们来看几个例子:

var x = 1;//数字x,基本类型  
var y = x;//数字y,基本类型  
print(x);  
print(y);     
x = 2;//修改x的值     
print(x);//x的值变为2  
print(y);//y的值不会变化


运行结果如下:

1

1

2

1


这样的运行结果应该在你的意料之内,没有什么特别之处,我们再来看看引用类型的例子,由于数组的长度非固定,可以动态增删,因此数组为引用类型:

var array = [1,2,3,4,5];  
var arrayRef = array;     
array.push(6);  
print(arrayRef);


引用指向的是地址,也就是说,引用不会指向引用本身,而是指向该引用所对应的实际对象。因此通过修改array指向的数组,则arrayRef指向的是同一个对象,因此运行效果如下:

1,2,3,4,5,6


2.2.2变量的作用域

变量被定义的区域即为其作用域,全局变量具有全局作用域;局部变量,比如声明在函数内部的变量则具有局部作用域,在函数的外部是不能直接访问的。比如:

var variable = "out";     
function func(){      
var variable = "in";      
print(variable);//打印”in”  
}     
func();  
print(variable);//打印”out”


应该注意的是,在函数内var关键字是必须的,如果使用了变量而没有写var关键字,则默认的操作是对全局对象的,比如:

var variable = "out";     
function func(){      
variable = "in";//注意此variable前没有var关键字     
print(variable);  
}     
func();  
print(variable);//全局的变量variable被修改


由于函数func中使用variable而没有关键字var,则默认是对全局对象variable属性做的操作(修改variable的值为in),因此此段代码会打印:

in

in


2.3运算符

运算符,通常是容易被忽略的一个内容,但是一些比较古怪的语法现象仍然可能需要用到运算符的结合率或者其作用来进行解释,JavaScript中,运算符是一定需要注意的地方,有很多具有JS编程经验的人仍然免不了被搞得晕头转向。

我们在这一节主要讲解这样几个运算符:

2.3.1中括号运算符([])

[]运算符可用在数组对象和对象上,从数组中按下标取值:

var array = ["one", "two", "three", "four"]; 
array[0]


而[]同样可以作用于对象,一般而言,对象中的属性的值是通过点(.)运算符来取值,如:

var object = 
{      
field : "self",      printInfo : function(){         
print(this.field);      
}  
}     
object.field;  
object.printInfo();


但是考虑到这样一种情况,我们在遍历一个对象的时候,对其中的属性的键(key)是一无所知的,我们怎么通过点(.)来访问呢?这时候我们就可以使用[]运算符:

for(var key in object){      
print(key + ":" + object[key]);  
}


运行结果如下:

field:slef  
printInfo:function (){         print(this.field);  }


2.3.2点运算符(.)

点运算符的左边为一个对象(属性的集合),右边为属性名,应该注意的是右边的值除了作为左边的对象的属性外,同时还可能是它自己的右边的值的对象:

<strong>var object = {      field : "self",      printInfo : function(){         print(this.field);      },      outter:{         inner : "inner text",         printInnerText : function(){             print(this.inner);         }      }  }     object.outter.printInnerText();</strong> 这个例子中,outter作为object的属性,同时又是printInnerText()的对象。

2.3.3 == 和 === 以及 != 和 !==

运算符==读作相等,而运算符===则读作等同。这两种运算符操作都是在JavaScript代码中经常见到的,但是意义则不完全相同,简而言之,相等操作符会对两边的操作数做类型转换,而等同则不会。我们还是通过例子来说明:

print(1 == true);  
print(1 === true);  
print("" == false);  
print("" === false);     
print(null == undefined);  
print(null === undefined); 


运行结果如下:

true 
false 
true 
false 
true 
false


相等和等同运算符的规则分别如下:

相等运算符

如果操作数具有相同的类型,则判断其等同性,如果两个操作数的值相等,则返回true(相等),否则返回false(不相等).

如果操作数的类型不同,则按照这样的情况来判断:

◆  null和undefined相等

◆ 其中一个是数字,另一个是字符串,则将字符串转换为数字,再做比较

◆  其中一个是true,先转换成1(false则转换为0)在做比较

◆ 如果一个值是对象,另一个是数字/字符串,则将对象转换为原始值(通过toString()或者valueOf()方法)

◆ 其他情况,则直接返回false

等同运算符

如果操作数的类型不同,则不进行值的判断,直接返回false

如果操作数的类型相同,分下列情况来判断:

◆ 都是数字的情况,如果值相同,则两者等同(有一个例外,就是NaN,NaN与其本身也不相等),否则不等同

◆ 都是字符串的情况,与其他程序设计语言一样,如果串的值不等,则不等同,否则等同

◆ 都是布尔值,且值均为true/false,则等同,否则不等同

◆ 如果两个操作数引用同一个对象(数组,函数),则两者完全等同,否则不等同

◆ 如果两个操作数均为null/undefined,则等同,否则不等同

比如:

var obj = {
      id : "self",
      name : "object" };
var oa = obj;
var ob = obj;     
print(oa == ob);  
print(oa === ob);

会返回:

true

true


再来看一个对象的例子:

var obj1 = {
      id : "self",
      name : "object",
      toString : function(){
         return "object 1";
      }
  }     
var obj2 = "object 1";     
print(obj1 == obj2);  
print(obj1 === obj2);


返回值为:

true

false


obj1是一个对象,而obj2是一个结构与之完全不同的字符串,而如果用相等操作符来判断,则两者是完全相同的,因为obj1重载了顶层对象的toString()方法。

而!=不等和!==不等同,则与==/!==相反。因此,在JavaScript中,使用相等/等同,不等/不等同的时候,一定要注意类型的转换,这里推荐使用等同/不等同来进行判断,这样可以避免一些难以调试的bug。

原文:http://abruzzi.iteye.com/blog/632010


分享到:
评论

相关推荐

    javascript核心

    1.2 JavaScript内核系列 第2章 基本概念 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 1.3 JavaScript内核系列 第3章 对象与JSON . . . . . . . . . ...

    microkernel:服务器应用程序的微内核

    安装$ npm install microkernel基本概念微内核设计遵循状态转换、模块组和标签、模块依赖项和模块定义的主要概念。状态转换微内核可以处于多种状态。为了在状态之间转换,微内核在所有拓扑排序的模块上以(反向)...

    Analysis-of-PureScripts-Compilation-Process:通过查看函数式语言的实现方式来理解它们的概念。 源语言是PureScript,可编译为JavaScript。 该论文是在一个学期的大学项目中用德语撰写的。 也许它也可以帮助正在使用函数式编程的任何人

    事实证明,一开始的障碍比较大,难以理解基本概念(例如,当使用类型类并已经简单地添加了整数时),然后通过更高级的概念(例如函子或monads)谈论它们而变得更加容易,并且了解它们之后,首先将基本概念内在化。...

    python入门到高级全栈工程师培训 第3期 附课件代码

    02 Django的ORM基本操作补充之一对多 03 学员管理示例:编辑学生 04 Django的ORM基本操作补充之多对多 05 学员管理示例:为班级分配老师 06 初识Ajax以及简单应用 07 学员管理示例:Ajax删除学生 08 本节作业以及...

    C程序设计语言(第2版·新版中文)

    全面、系统地讲述了C语言的各个特性及程序设计的基本方法,包括基本概念,类型和表达式、控制流、函数与程序结构、指针与数组、结构、输入与输出、UNIX系统接口、标准库等内容。 目录   出版者的话 专家指导委员...

    详解JS浏览器事件循环机制

    线程是进程的执行流,是CPU调度和分派的基本单位,同个进程之中的多个线程之间是共享该进程的资源的。 浏览器内核 浏览器是多进程的,浏览器每一个 tab 标签都代表一个独立的进程(也不一定,因为多个空白 tab 标签...

    代码之美(中文完整版).pdf

    第16章,Linux内核驱动模型:协作的好处 16.1 简单的开始 16.2 进一步简化 16.3 扩展到上千台设备 16.4 小对象的松散结合 第17章 额外的间接层 17.1. 从直接代码操作到通过函数指针操作 17.2. 从函数参数到参数指针 ...

    Android基础教程

    第2章 基本概念 2.1 Android的系统架构 2.1.1 Linux内核 2.1.2 本机库 2.1.3 Android运行时 2.1.4 应用程序框架 2.1.5 应用程序和小部件 2.2 它还活着 2.2.1 进程不等于应用程序 2.2.2 应用程序生命周期 2.3 构建块 ...

    Android程序设计基础

    第1~3章介绍Android的基础知识和基本概念;第4~6章介绍2D图形、多媒体和存储本地数据;第7~10章介绍高级主题,包括联网、定位与环境感知、数据库和3D图形;附录介绍了Android与Java之间的差别以及参考书目。  ...

    工程硕士学位论文 基于Android+HTML5的移动Web项目高效开发探究

    Chrome Frame 会把最新版的Chrome Webkit 内核和JavaScript 引擎注入到IE中, IE浏览器将获得Chrome的性能和功能 目录 摘要 I ABSTRACT II 专业名词清单 III 第一章 绪论 1 1.1 研究背景与意义 1 1.2国内外相关...

    Tcl_TK编程权威指南pdf

    基本概念 创建可加载软件包 一个用c语言实现的命令过程 blob命令的例于 字符串与国际化 tolmain和tcl-applnit tk_main 事件循环 从c中调用脚本 第45章 编译tci及扩展模块 标准目录结构 从源代码建立tci ...

    ActionScript开发技术大全

    3.9.1函数的基本概念 60 3.9.2函数定义与调用 60 3.9.3函数的参数 63 3.9.4函数的返回值 66 3.9.5函数对象 66 3.9.6函数的生存周期 67 3.9.7递归函数 68 3.9.8全局函数 69 3.10小结 72 第2篇ActionScript3.0面向对象...

Global site tag (gtag.js) - Google Analytics