`
abruzzi
  • 浏览: 444290 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

JavaScript内核系列 第2章 基本概念

阅读更多

 

第二章 基本概念

本章将聚焦于JavaScript中的基本概念,这些概念与传统语言有比较大的不同,因此单独列出一章来做专门描述,理解本章的概念对书中后续章节的概念,代码的行为等会有很大的帮助,读者不妨花比较大的时间在本章,即使你对JavaScript已经比较熟悉,也建议通读本章。

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

2.1数据类型

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

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

2.1.1 基本数据类型

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

 

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

 

 

 

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

 

 

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是一个一元的操作符,在本章的另外一个小节会专门讲到。

2.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);
 

 

 

 

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

   

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

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

事实上,这种转换规则会导致很多的问题,比如,所有的非空对象,在布尔值环境下,都会被转成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和数组arraytypeof值均为”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点运算符(.)

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

 

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

 

 

 

这个例子中,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(不相等).

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

l  nullundefined相等

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

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

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

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

 

等同运算符

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

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

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

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

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

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

l  如果两个操作数均为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

 

 

 

附:由于作者本身水平有限,文中难免有纰漏错误等,或者语言本身有不妥当之处,欢迎及时指正,提出建议,参与讨论,谢谢大家!

分享到:
评论
41 楼 wowxndnaken 2011-03-23  
1.var str = "Hello, world";  
2.var obj = new Object();  
3.obj.str = str;  
4.obj.num = 2.3;  
5.   
6.var array = new Array("foo", "bar", "zoo");  
7.   
8.var func = function(){  
9.    print("I am a function here");  
10.} 

array 的类型是function  func返回的是undefined
40 楼 abruzzi 2010-05-12  
389yufeng 写道
有一问题:
var bool = new Boolean(false);
var bool1 = false;
function cont(){
   if(bool){    //if(bool1) 不执行
      alert(bool)
   }
}

这两种定义有什么区别,两者最后的值都false,为什么对象定义类型能执行???


这个跟JavaScript的类型判断/转换机制有关系:
var bool = new Boolean(false);//这是一个Boolean对象,
if(bool){//此时判断bool是否为空或undefined,相当于if(bool == null || bool == undefined),因此返回true
}


而对象直接量在判断是并非作为一个对象来判断的,简而言之,可以看下这两者在实际运行环境中的类型:
typeof bool1
boolean
typeof bool
object


bool1的值为false,因此不会执行,而bool为一个非空的对象,因此if会将其转换为true(相当于bool == null?)
39 楼 389yufeng 2010-05-12  
有一问题:
var bool = new Boolean(false);
var bool1 = false;
function cont(){
   if(bool){    //if(bool1) 不执行
      alert(bool)
   }
}

这两种定义有什么区别,两者最后的值都false,为什么对象定义类型能执行???
38 楼 abruzzi 2010-04-21  
fantasybei 写道
有的,var obj = {"first-name": 'Fan', first_name: 'fan'};
你可以试试obj.first_name,obj.first-name,obj["first-name"]
变量名中包含.只是非法变量名的一种。


我感觉这个有点绕,但应该不是“非法”的问题,解释器在解释到obj.first-name时,
不知道是obj的first属性来“减”name的值,还是obj.first-name。

根本原因应该是在[]操作符里,是以字符串做索引的,因此没有问题。而点操作符不是用字符串,而是
去遍历对象的属性列表(不是用字符串)而导致的。
37 楼 fantasybei 2010-04-21  
有的,var obj = {"first-name": 'Fan', first_name: 'fan'};
你可以试试obj.first_name,obj.first-name,obj["first-name"]
变量名中包含.只是非法变量名的一种。
36 楼 abruzzi 2010-04-21  
fantasybei 写道
-_-!!!,对于对象属性的访问,可以加上.和[]的一点小区别,如果属性是合法的变量名,则两个都可以用,反之只能用[]


没有合法不合法之说吧?
如果属性中包含点号(.)则只能用[],没有点号的两者均可。
35 楼 fantasybei 2010-04-21  
-_-!!!,对于对象属性的访问,可以加上.和[]的一点小区别,如果属性是合法的变量名,则两个都可以用,反之只能用[]
34 楼 abruzzi 2010-04-18  
JavaScript内核之第四章,地址如下:
http://www.iteye.com/topic/646798
33 楼 abruzzi 2010-04-12  
JavaScript内核之第三章,地址如下:
http://www.iteye.com/topic/641532
32 楼 abruzzi 2010-04-09  
大家好,为了便于此系列的阅读,方便大家和我交流,指正我的错误,我在JavaEye申请了“JavaScript内核”专栏,现已获批准,大家可以加入此专栏进行讨论,谢谢!

专栏地址如下:
http://www.iteye.com/wiki/javascript-core
31 楼 abruzzi 2010-04-09  
jackami121 写道
期待 后续这几章
第七章 闭包
7.1闭包的特性
7.2闭包的用途
7.3应该注意的问题

第八章 面向对象的Javascript
8.1 原型继承
8.1.1引用
8.1.2 new操作符
8.2封装与继承
8.3 工具包Base
8.4实例:事件分发器

第九章 函数式的Javascript
9.1匿名函数
9.2高阶函数
9.3闭包与Currying
9.4一些例子



谢谢关注,后边的章节基本已经完成,文字方面可能还需要润色,个别细节还需要斟酌,请耐心等待,呵呵。
30 楼 jackami121 2010-04-09  
期待 后续这几章
第七章 闭包
7.1闭包的特性
7.2闭包的用途
7.3应该注意的问题

第八章 面向对象的Javascript
8.1 原型继承
8.1.1引用
8.1.2 new操作符
8.2封装与继承
8.3 工具包Base
8.4实例:事件分发器

第九章 函数式的Javascript
9.1匿名函数
9.2高阶函数
9.3闭包与Currying
9.4一些例子
29 楼 舞指如歌 2010-04-08  
看了第一期,终于找到第二期了,希望继续发表好的文章
28 楼 abruzzi 2010-04-08  
yangpeihai 写道
JavaScript Core Chapter 2

你把整个文章贴一遍,是么子意思呢?
27 楼 yangpeihai 2010-04-08  
<div class="quote_title">abruzzi 写道</div>
<div class="quote_div">
<p> </p>
<h2>
<a name="_Toc252397742"><span>第二章</span> </a><span><span>基本概念</span></span>
</h2>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>本章将聚焦于</span><span lang="EN-US">JavaScript</span><span>中的基本概念,这些概念与传统语言有比较大的不同,因此单独列出一章来做专门描述,理解本章的概念对书中后续章节的概念,代码的行为等会有很大的帮助,读者不妨花比较大的时间在本章,即使你对</span><span lang="EN-US">JavaScript</span><span>已经比较熟悉,也建议通读本章。</span></p>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>本章主要讲述</span><span lang="EN-US">JavaScript</span><span>中的数据类型</span><span lang="EN-US">(</span><span>基本类型与引用类型</span><span lang="EN-US">)</span><span>,变量</span><span lang="EN-US">(</span><span>包括变量的作用域</span><span lang="EN-US">)</span><span>,操作符</span><span lang="EN-US">(</span><span>主要是一些较为常见,但是不容易从字面上理解的操作符</span><span lang="EN-US">)</span><span>。由于</span><span lang="EN-US">JavaScript</span><span>中的“<strong><em><span style="font-size: small;">一切皆对象</span></em></strong>”,在掌握了这些基本的概念之后,读者就可以较为轻松的理解诸如作用域,调用对象,闭包,</span><span lang="EN-US">currying</span><span>等等较难理解的概念了。</span></p>
<h3>
<a name="_Toc252397743"><span lang="EN-US">2.1</span></a><span><span>数据类型</span></span>
</h3>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>有程序设计经验的读者肯定知道,在</span><span lang="EN-US">C</span><span>或者</span><span lang="EN-US">Java</span><span>这样的语言中,数据是有类型的,比如用以表示用户名的属性是字符串,而一个雇员的年龄则是一个数字,表示</span><span lang="EN-US">UI</span><span>上的一个开关按钮的数据模型则为布尔值等等,对数字可能还可以细分为浮点数,整型数,整型数又可能分为长整型和短整型,总而言之,它们都表示语言中的数据的值的类型。</span></p>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span lang="EN-US">JavaScript</span><span>中的数据类型分为两种:基本数据类型和对象类型,其中对象类型包含对象,数组,以及函数(事实上,函数,数组等也都是对象,这个在后边的章节详述)。</span></p>
<h4>
<a name="_Toc252397744"><span lang="EN-US">2.1.1 </span></a><span><span>基本数据类型</span></span>
</h4>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>在</span><span lang="EN-US">JavaScript</span><span>中,包含三种基本的数据类型,字符串</span><span lang="EN-US">(String)</span><span>,数值</span><span lang="EN-US">(Number)</span><span>,布尔值</span><span lang="EN-US">(boolean)</span><span>,下面是一些简单的例子:</span></p>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><span style="font-size: 13px;"><strong></strong></span></span></p>
<p><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><strong>
</strong></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">var str = "Hello, world";//字符串
var i = 10;//整型数
var f = 2.3;//浮点数

var b = true;//布尔值</pre>
 </strong>
<p> </p>
<p> </p>
<p> </p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal"><span>我们可以分别查看变量的值及变量的类型:</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left;" align="left"> </p>
<p><span style="font-family: 'Courier New'; color: #0064c8; font-size: small;">
</span></p>
<pre name="code" class="js">print(str);
print(i);
print(f);
print(b);

print(typeof str);
print(typeof i);
print(typeof f);
print(typeof b);</pre>
 
<p> </p>
<p> </p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal"><span>注意,在此处使用的</span><span style="font-size: 10.0pt;" lang="EN-US">print()</span><span>函数为</span><span style="font-size: 10.0pt;" lang="EN-US">rhino</span><span>解释器的顶层对象的方法,可以用来打印字符串,通常情况下,在客户端,程序员多使用</span><span style="font-size: 10.0pt;" lang="EN-US">alert()</span><span>进行类似的动作,</span><span style="font-size: 10.0pt;" lang="EN-US">alert()</span><span>是浏览器中</span><span style="font-size: 10.0pt;" lang="EN-US">JavaScript</span><span>解释器的顶层对象</span><span style="font-size: 10.0pt;" lang="EN-US">(window)</span><span>的一个方法。</span></p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left;" align="left"> </p>
<p><span style="font-family: 'Courier New'; font-size: small;">
</span></p>
<pre name="code" class="js">Hello, world
10
2.3
true

string
number
number
Boolean</pre>
 
<p> </p>
<p> </p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal"><span>在</span><span lang="EN-US">JavaScript</span><span>中,所有的数字,不论是整型浮点,都属于“数字”基本类型。</span><span lang="EN-US">typeof</span><span>是一个一元的操作符,在本章的另外一个小节会专门讲到。</span></p>
<h4>
<a name="_Toc252397745"><span lang="EN-US">2.1.2 </span></a><span><span>对象类型</span></span>
</h4>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>这里提到的对象不是对象本身,而是指一种类型,我们在第三章会对对象进行详细的讨论,此处的对象包括,对象</span><span lang="EN-US">(</span><span>属性的集合,即键值的散列表</span><span lang="EN-US">)</span><span>,数组</span><span lang="EN-US">(</span><span>有序的列表</span><span lang="EN-US">)</span><span>,函数</span><span lang="EN-US">(</span><span>包含可执行的代码</span><span lang="EN-US">)</span><span>。</span></p>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>对象类型是一种复合的数据类型,其基本元素由基本数据类型组成,当然不限于基本类型,比如对象类型中的值可以是其他的对象类型实例,我们通过例子来说明:</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><strong><span style="font-size: 10.0pt;" lang="EN-US"> </span></strong></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><span style="font-size: 13px;"><strong></strong></span></span></p>
<p><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><strong>
</strong></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">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");
}</pre>
 </strong>
<p> </p>
<p> </p>
<p> </p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>可以看到,对象具有属性,如</span><span lang="EN-US">obj.str, obj.num</span><span>,这些属性的值可以是基本类型,事实上还可以更复杂,我们来看看他们的类型:</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left;" align="left"> </p>
<p><span style="font-family: 'Courier New'; color: #0064c8; font-size: small;">
</span></p>
<pre name="code" class="js">print(typeof obj);
print(typeof array);
print(typeof func);

//将打印出
object
object
function</pre>
 
<p> </p>
<p> </p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal"><span lang="EN-US"><span>         </span></span><span>读者可能会对</span><span lang="EN-US">print(typeof array)</span><span>打印出</span><span lang="EN-US">object</span><span>感到奇怪,事实上,对象和数组的界限并不那么明显</span><span lang="EN-US">(</span><span>事实上它们是属于同一类型的</span><span lang="EN-US">)</span><span>,但是他们的行为却非常不同,本书的后续章节将两个重要的数据类型做了分别介绍。</span></p>
<h4>
<a name="_Toc252397746"><span lang="EN-US">2.1.3 </span></a><span><span>两者之间的转换</span></span>
</h4>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>类似与</span><span lang="EN-US">Java</span><span>中基本数据类型的自动装箱拆箱,</span><span lang="EN-US">JavaScript</span><span>也有类似的动作,基本数据类型在做一些运算时,会临时包装一个对象,做完运算后,又自动释放该对象。我们可以通过几个例子来说明:</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><strong><span style="font-size: 10.0pt;" lang="EN-US"> </span></strong></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><span style="font-size: 13px;"><strong></strong></span></span></p>
<p><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><strong>
</strong></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">var str = "JavaScript Kernal";
print(str.length);//打印17</pre>
 </strong>
<p> </p>
<p> </p>
<p> </p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal"><span lang="EN-US">str</span><span>为一个字符串,通过</span><span lang="EN-US">typeof运算符</span><span>可知其</span><span lang="EN-US">type</span><span>为</span><span lang="EN-US">”string”</span><span>,而:</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><span style="font-size: 13px;"><strong></strong></span></span></p>
<p><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><strong>
</strong></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">var str2 = new String("JavaScript Kernal");

print(typeof str2);</pre>
 </strong>
<p> </p>
<p> </p>
<p> </p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>可知,</span><span style="font-size: 10.0pt;" lang="EN-US">str2</span><span>的</span><span style="font-size: 10.0pt;" lang="EN-US">type</span><span>为</span><span style="font-size: 10.0pt;" lang="EN-US">”object”</span><span>,即这两者并不相同,那么为什么可以使用</span><span style="font-size: 10.0pt;" lang="EN-US">str.length</span><span>来的到</span><span style="font-size: 10.0pt;" lang="EN-US">str</span><span>的长度呢?事实上,当使用</span><span style="font-size: 10.0pt;" lang="EN-US">str.length</span><span>时,</span><span style="font-size: 10.0pt;" lang="EN-US">JavaScript</span><span>会自动包装一个临时的</span><span style="font-size: 10.0pt;" lang="EN-US">String</span><span>对象,内容为</span><span style="font-size: 10.0pt;" lang="EN-US">str</span><span>的内容,然后获取该对象的</span><span style="font-size: 10.0pt;" lang="EN-US">length</span><span>属性,最后,这个临时的对象将被释放。</span></p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"><span>    </span></span></p>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>而将对象转换为基本类型则是通过这样的方式:通过调用对象的</span><span lang="EN-US">valueOf()</span><span>方法来取得对象的值,如果和上下文的类型匹配,则使用该值。如果</span><span lang="EN-US">valueOf</span><span>取不到值的话,则需要调用对象的</span><span lang="EN-US">toString()</span><span>方法,而如果上下文为数值型,则又需要将此字符串转换为数值。由于</span><span lang="EN-US">JavaScript</span><span>是弱类型的,所以</span><span lang="EN-US">JavaScript</span><span>引擎需要根据上下文来“猜测”对象的类型,这就使得</span><span lang="EN-US">JavaScript</span><span>的效率比编译型的语言要差一些。</span></p>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span lang="EN-US">valueOf()</span><span>的作用是,将一个对象的值转换成一种合乎上下文需求的基本类型,</span><span lang="EN-US">toString()</span><span>则名副其实,可以打印出对象对应的字符串</span><span lang="EN-US">,</span><span>当然前提是你已经“重载”了</span><span lang="EN-US">Object</span><span>的</span><span lang="EN-US">toString()</span><span>方法。</span></p>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>事实上,这种转换规则会导致很多的问题,比如,所有的非空对象,在布尔值环境下,都会被转成</span><span lang="EN-US">true</span><span>,比如:</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><strong><span style="font-size: 10.0pt;" lang="EN-US"> </span></strong></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><span style="font-size: 13px;"><strong></strong></span></span></p>
<p><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><strong>
</strong></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">function convertTest(){
if(new Boolean(false) &amp;&amp; new Object() &amp;&amp;
new String("") &amp;&amp; new Array()){
       print("convert to boolean")
    } 
}

convertTest();//convert to Boolean</pre>
 </strong>
<p> </p>
<p> </p>
<p> </p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>初学者容易被</span><span lang="EN-US">JavaScript</span><span>中的类型转换规则搞晕掉,很多情况下会觉得那种写法看着非常别扭,其实只需要掌握了规则,这些古怪的写法会大大的提高代码的性能,我们通过例子来学习这些规则:</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><strong><span style="font-size: 10.0pt;" lang="EN-US"> </span></strong></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><span style="font-size: 13px;"><strong></strong></span></span></p>
<p><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><strong>
</strong></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">var x = 3;
var y = x + "2";// =&gt; 32
var z = x + 2;// =&gt; 5

print(y);
print(z);</pre>
 </strong>
<p> </p>
<p> </p>
<p> </p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal"><span>通常可以在</span><span lang="EN-US">JS</span><span>代码中发现这样的代码:</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><strong><span style="font-size: 10.0pt;" lang="EN-US"> </span></strong></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><span style="font-size: 13px;"><strong></strong></span></span></p>
<p><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><strong>
</strong></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">if(datamodel.item){
    //do something...
}else{
    datamodel.item = new Item();
}</pre>
 </strong>
<p> </p>
<p> </p>
<p> </p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal"><span>这种写法事实上具有更深层次的含义:</span></p>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>应该注意到,</span><span lang="EN-US">datamodel.item</span><span>是一个对象</span><span lang="EN-US">(</span><span>字符串,数字等</span><span lang="EN-US">)</span><span>,而</span><span lang="EN-US">if</span><span>需要一个</span><span lang="EN-US">boolean</span><span>型的表达式,所以这里进行了类型转换。在</span><span lang="EN-US">JavaScript</span><span>中,如果上下文需要</span><span lang="EN-US">boolean</span><span>型的值,则引擎会自动将对象转换为</span><span lang="EN-US">boolean</span><span>类型。转换规则为,如果该对象非空,则转换为</span><span lang="EN-US">true,</span><span>否则为</span><span lang="EN-US">false.</span><span>因此我们可以采取这种简写的形式。</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal"><span>而在传统的编程语言</span><span lang="EN-US">(</span><span>强类型</span><span lang="EN-US">)</span><span>中,我们则需要:</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><span style="font-size: 13px;"><strong></strong></span></span></p>
<p><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><strong>
</strong></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">if(datamodel.item != null){
    //do something...
}else{
    datamodel.item = new Item();
}</pre>
 </strong>
<p> </p>
<p> </p>
<p> </p>
<h4>
<a name="_Toc252397747"><span lang="EN-US">2.1.4</span></a><span><span>类型的判断</span></span>
</h4>
<p class="MsoNormal"><span>前面讲到</span><span lang="EN-US">JavaScript</span><span>特性的时候,我们说过,</span><span lang="EN-US">JavaScript</span><span>是一个弱类型的语言,但是有时我们需要知道变量在运行时的类型,比如,一个函数的参数预期为另一个函数:</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><span style="font-size: 13px;"><strong></strong></span></span></p>
<p><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><strong>
</strong></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">function handleMessage(message, handle){
    return handle(message);
}</pre>
 </strong>
<p> </p>
<p> </p>
<p> </p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal"><span>当调用</span><span style="font-size: 10.0pt;" lang="EN-US">handleMessage</span><span>的函数传递的</span><span style="font-size: 10.0pt;" lang="EN-US">handle</span><span>不是一个函数则</span><span style="font-size: 10.0pt;" lang="EN-US">JavaScript</span><span>引擎会报错,因此我们有必要在调用之前进行判断:</span></p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><span style="font-size: 13px;"><strong></strong></span></span></p>
<p><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><strong>
</strong></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">function handleMessage(message, handle){
    if(typeof handle == "function"){
       return handle(message);
    }else{
       throw new Error("the 2nd argument should be a function");
    }
}</pre>
 </strong>
<p> </p>
<p> </p>
<p> </p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal"><span>但是,</span><span lang="EN-US">typeof</span><span>并不总是有效的,比如下面这种情况:</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><span style="font-size: 13px;"><strong></strong></span></span></p>
<p><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><strong>
</strong></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">var obj = {};
var array = ["one", "two", "three", "four"];

print(typeof obj);//object
print(typeof array); //object</pre>
 </strong>
<p> </p>
<p> </p>
<p> </p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal"><span>运行结果显示,对象</span><span lang="EN-US">obj</span><span>和数组</span><span lang="EN-US">array</span><span>的</span><span lang="EN-US">typeof</span><span>值均为</span><span lang="EN-US">”object”</span><span>,这样我们就无法准确判断了,这时候,可以通过调用</span><span lang="EN-US">instanceof</span><span>来进行进一步的判断:</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left;" align="left"> </p>
<p><span style="font-family: 'Courier New'; color: #0064c8; font-size: small;">
</span></p>
<pre name="code" class="js">print(obj instanceof Array);//false
print(array instanceof Array);//true</pre>
 
<p> </p>
<p> </p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal"><span>第一行代码返回</span><span lang="EN-US">false,</span><span>第二行则返回</span><span lang="EN-US">true</span><span>。因此,我们可以将</span><span lang="EN-US">typeof</span><span>操作符和</span><span lang="EN-US">instanceof</span><span>操作符结合起来进行判断。</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<h3>
<a name="_Toc252397748"><span lang="EN-US">2.2 </span></a><span><span>变量</span></span>
</h3>
<p class="MsoNormal"><span>变量,即通过一个名字将一个值关联起来,以后通过变量就可以引用到该值,比如:</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><strong><span style="font-size: 10.0pt;" lang="EN-US"> </span></strong></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><span style="font-size: 13px;"><strong></strong></span></span></p>
<p><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><strong>
</strong></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">var str = "Hello, World";
var num = 2.345;</pre>
 </strong>
<p> </p>
<p> </p>
<p> </p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal"><span>当我们下一次要引用</span><span lang="EN-US">”Hello, Wrold”</span><span>这个串进行某项操作时,我们只需要使用变量</span><span lang="EN-US">str</span><span>即可,同样,我们可以用</span><span lang="EN-US">10*num </span><span>来表示</span><span lang="EN-US">10*2.345</span><span>。变量的作用就是将值“存储”在这个变量上。</span> </p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<h4>
<a name="_Toc252397749"><span lang="EN-US">2.2.1</span></a><span><span>基本类型和引用类型</span></span>
</h4>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>在上一小节,我们介绍了</span><span lang="EN-US">JavaScript</span><span>中的数据类型,其中基本类型如数字,布尔值,它们在内存中都有固定的大小,我们通过变量来直接访问基本类型的数据。而对于引用类型,如对象,数组和函数,由于它们的大小在原则上是不受任何限制的,故我们通过对其引用的访问来访问它们本身,引用本身是一个地址,即指向真实存储复杂对象的位置。</span></p>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>基本类型和引用类型的区别是比较明显的,我们来看几个例子:</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><strong><span style="font-size: 10.0pt;" lang="EN-US"> </span></strong></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><span style="font-size: 13px;"><strong></strong></span></span></p>
<p><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><strong>
</strong></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">var x = 1;//数字x,基本类型
var y = x;//数字y,基本类型
print(x);
print(y);

x = 2;//修改x的值

print(x);//x的值变为2
print(y);//y的值不会变化</pre>
 </strong>
<p> </p>
<p> </p>
<p> </p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal"><span>运行结果如下:</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"> </p>
<p><span style="font-family: 'Courier New'; font-size: small;">
</span></p>
<div class="quote_div">1<br>1<br>2<br>1</div>
 
<p> </p>
<p> </p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal"><span>这样的运行结果应该在你的意料之内,没有什么特别之处,我们再来看看引用类型的例子,由于数组的长度非固定,可以动态增删,因此数组为引用类型:</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><span style="font-size: 13px;"><strong></strong></span></span></p>
<p><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><strong>
</strong></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">var array = [1,2,3,4,5];
var arrayRef = array;

array.push(6);
print(arrayRef);</pre>
 </strong>
<p> </p>
<p> </p>
<p> </p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal"><span>引用指向的是地址,也就是说,引用不会指向引用本身,而是指向该引用所对应的实际对象。因此通过修改</span><span lang="EN-US">array</span><span>指向的数组,则</span><span lang="EN-US">arrayRef</span><span>指向的是同一个对象,因此运行效果如下:</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left;" align="left"> </p>
<p><span style="font-family: 'Courier New'; font-size: small;">
</span></p>
<div class="quote_div">1,2,3,4,5,6</div>
 
<p> </p>
<p> </p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<h4>
<a name="_Toc252397750"><span lang="EN-US">2.2.2</span></a><span><span>变量的作用域</span></span>
</h4>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>变量被定义的区域即为其作用域,全局变量具有全局作用域;局部变量,比如声明在函数内部的变量则具有局部作用域,在函数的外部是不能直接访问的。比如:</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><strong><span style="font-size: 10.0pt;" lang="EN-US"> </span></strong></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><span style="font-size: 13px;"><strong></strong></span></span></p>
<p><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><strong>
</strong></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">var variable = "out";

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

func();
print(variable);//打印”out”</pre>
 </strong>
<p> </p>
<p> </p>
<p> </p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>应该注意的是,在函数内</span><span lang="EN-US">var</span><span>关键字是必须的,如果使用了变量而没有写</span><span lang="EN-US">var</span><span>关键字,则默认的操作是对全局对象的,比如:</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><span style="font-size: 13px;"><strong></strong></span></span></p>
<p><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><strong>
</strong></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">var variable = "out";

function func(){
    variable = "in";//注意此variable前没有var关键字
    print(variable);
}

func();
print(variable);//全局的变量variable被修改</pre>
 </strong>
<p> </p>
<p> </p>
<p> </p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>由于函数</span><span lang="EN-US">func</span><span>中使用</span><span lang="EN-US">variable</span><span>而没有关键字</span><span lang="EN-US">var,</span><span>则默认是对全局对象</span><span lang="EN-US">variable</span><span>属性做的操作</span><span lang="EN-US">(</span><span>修改</span><span lang="EN-US">variable</span><span>的值为</span><span lang="EN-US">in)</span><span>,因此此段代码会打印:</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><span style="font-size: 13px;"><strong></strong></span></span></p>
<p><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><strong>
</strong></span></p>
<p><strong>
</strong></p>
<strong>
<div class="quote_div">in<br>in</div>
 </strong>
<p> </p>
<p> </p>
<p> </p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<h3>
<a name="_Toc252397751"><span lang="EN-US">2.3</span></a><span><span>运算符</span></span>
</h3>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>运算符,通常是容易被忽略的一个内容,但是一些比较古怪的语法现象仍然可能需要用到运算符的结合率或者其作用来进行解释,</span><span lang="EN-US">JavaScript</span><span>中,运算符是一定需要注意的地方,有很多具有</span><span lang="EN-US">JS</span><span>编程经验的人仍然免不了被搞得晕头转向。</span></p>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>我们在这一节主要讲解这样几个运算符:</span></p>
<h4>
<a name="_Toc252397752"><span lang="EN-US">2.3.1中</span></a><span><span>括号运算符</span><span lang="EN-US">([])</span></span>
</h4>
<p class="MsoNormal"><span lang="EN-US"><strong><span style="color: #000080;">[]</span></strong></span><span>运算符可用在数组对象和对象上,从数组中按下标取值:</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><span style="font-size: 13px;"><strong></strong></span></span></p>
<p><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><strong>
</strong></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">var array = ["one", "two", "three", "four"];
array[0]</pre>
 </strong>
<p> </p>
<p> </p>
<p> </p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal"><span>而</span><span lang="EN-US">[]</span><span>同样可以作用于对象,一般而言,对象中的属性的值是通过点</span><span lang="EN-US">(.)</span><span>运算符来取值,如:</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><span style="font-size: 13px;"><strong></strong></span></span></p>
<p><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><strong>
</strong></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">var object = {
    field : "self",
    printInfo : function(){
       print(this.field);
    }
}

object.field;
object.printInfo();</pre>
 </strong>
<p> </p>
<p> </p>
<p> </p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal"><span>但是考虑到这样一种情况,我们在遍历一个对象的时候,对其中的属性的键</span><span style="font-size: 10.0pt;" lang="EN-US">(key)</span><span>是一无所知的,我们怎么通过点</span><span style="font-size: 10.0pt;" lang="EN-US">(.)</span><span>来访问呢?这时候我们就可以使用</span><span style="font-size: 10.0pt;" lang="EN-US">[]</span><span>运算符:</span></p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><span style="font-size: 13px;"><strong></strong></span></span></p>
<p><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><strong>
</strong></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">for(var key in object){
    print(key + ":" + object[key]);
}</pre>
 </strong>
<p> </p>
<p> </p>
<p> </p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal"><span>运行结果如下:</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left;" align="left"> </p>
<p><span style="font-family: 'Courier New'; font-size: small;">
</span></p>
<pre name="code" class="java">field:slef
printInfo:function (){
       print(this.field);
}</pre>
 
<p> </p>
<p> </p>
<h4>
<a name="_Toc252397753"><span lang="EN-US">2.3.2</span></a><span><span>点运算符</span><span lang="EN-US">(.)</span></span>
</h4>
<p class="MsoNormal"><span>点运算符的左边为一个对象</span><span lang="EN-US">(</span><span>属性的集合</span><span lang="EN-US">)</span><span>,右边为属性名,应该注意的是右边的值除了作为左边的对象的属性外,同时还可能是它自己的右边的值的对象:</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><span style="font-size: 13px;"><strong></strong></span></span></p>
<p><span style="font-family: 'Courier New'; color: #0000c8; font-size: small;"><strong>
</strong></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">var object = {
    field : "self",
    printInfo : function(){
       print(this.field);
    },
    outter:{
       inner : "inner text",
       printInnerText : function(){
           print(this.inner);
       }
    }
}

object.outter.printInnerText();</pre>
 </strong>
<p> </p>
<p> </p>
<p> </p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal"><span>这个例子中,</span><span lang="EN-US">outter</span><span>作为</span><span lang="EN-US">object</span><span>的属性,同时又是</span><span lang="EN-US">printInnerText()</span><span>的对象。</span></p>
<h4>
<a name="_Toc252397754"><span lang="EN-US">2.3.3 == </span></a><span><span>和</span><span lang="EN-US"> === </span></span><span><span>以及</span><span lang="EN-US"> != </span></span><span><span>和</span><span lang="EN-US"> !==</span></span>
</h4>
<p> </p>
<p> </p>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>运算符</span><span lang="EN-US">==</span><span>读作相等,而运算符</span><span lang="EN-US">===</span><span>则读作等同。这两种运算符操作都是在</span><span lang="EN-US">JavaScript</span><span>代码中经常见到的,但是意义则不完全相同,简而言之,相等操作符会对两边的操作数做类型转换,而等同则不会。我们还是通过例子来说明:</span><span lang="EN-US"><br><br></span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; font-size: small;"><span style="font-size: 13px;">
</span></span></p>
<pre name="code" class="js">print(1 == true);
print(1 === true);
print("" == false);
print("" === false);

print(null == undefined);
print(null === undefined);</pre>
 
<p> </p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal"><span>运行结果如下:</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #7f0055; font-size: small;"><span style="font-size: 13px;"><strong>
</strong></span></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">true
false
true
false
true
false</pre>
 </strong>
<p> </p>
<p> </p>
<p class="MsoNormal"><strong><span style="font-size: 10.0pt;" lang="EN-US"> </span></strong></p>
<p class="MsoNormal"><span>相等和等同运算符的规则分别如下:</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal"><strong><span>相等运算符</span></strong></p>
<p class="MsoNormal"><span>如果操作数具有相同的类型,则判断其等同性,如果两个操作数的值相等,则返回</span><span lang="EN-US">true(</span><span>相等</span><span lang="EN-US">)</span><span>,否则返回</span><span lang="EN-US">false(</span><span>不相等</span><span lang="EN-US">).</span></p>
<p class="MsoNormal"><span>如果操作数的类型不同,则按照这样的情况来判断:</span></p>
<p class="MsoNormal"><span style="font-family: Wingdings;" lang="EN-US"><span>l<span style="font: 7.0pt ;">  </span></span></span><span lang="EN-US">null</span><span>和</span><span lang="EN-US">undefined</span><span>相等</span></p>
<p class="MsoNormal"><span style="font-family: Wingdings;" lang="EN-US"><span>l<span style="font: 7.0pt ;">  </span></span></span><span>其中一个是数字,另一个是字符串,则将字符串转换为数字,在做比较</span></p>
<p class="MsoNormal"><span style="font-family: Wingdings;" lang="EN-US"><span>l<span style="font: 7.0pt ;">  </span></span></span><span>其中一个是</span><span lang="EN-US">true</span><span>,先转换成</span><span lang="EN-US">1(false</span><span>则转换为</span><span lang="EN-US">0)</span><span>在做比较</span></p>
<p class="MsoNormal"><span style="font-family: Wingdings;" lang="EN-US"><span>l<span style="font: 7.0pt ;">  </span></span></span><span>如果一个值是对象,另一个是数字</span><span lang="EN-US">/</span><span>字符串,则将对象转换为原始值</span><span lang="EN-US">(</span><span>通过</span><span lang="EN-US">toString()</span><span>或者</span><span lang="EN-US">valueOf()</span><span>方法</span><span lang="EN-US">)</span></p>
<p class="MsoNormal"><span style="font-family: Wingdings;" lang="EN-US"><span>l<span style="font: 7.0pt ;">  </span></span></span><span>其他情况,则直接返回</span><span lang="EN-US">false</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal"><strong><span>等同运算符</span></strong></p>
<p class="MsoNormal"><span>如果操作数的类型不同,则不进行值的判断,直接返回</span><span lang="EN-US">false</span></p>
<p class="MsoNormal"><span>如果操作数的类型相同,分下列情况来判断:</span></p>
<p class="MsoNormal"><span style="font-family: Wingdings;" lang="EN-US"><span>l<span style="font: 7.0pt ;">  </span></span></span><span>都是数字的情况,如果值相同,则两者等同</span><span lang="EN-US">(</span><span>有一个例外,就是</span><span lang="EN-US">NaN</span><span>,</span><span lang="EN-US">NaN</span><span>与其本身也不相等</span><span lang="EN-US">)</span><span>,否则不等同</span></p>
<p class="MsoNormal"><span style="font-family: Wingdings;" lang="EN-US"><span>l<span style="font: 7.0pt ;">  </span></span></span><span>都是字符串的情况,与其他程序设计语言一样,如果串的值不等,则不等同,否则等同</span></p>
<p class="MsoNormal"><span style="font-family: Wingdings;" lang="EN-US"><span>l<span style="font: 7.0pt ;">  </span></span></span><span>都是布尔值,且值均为</span><span lang="EN-US">true/false</span><span>,则等同,否则不等同</span></p>
<p class="MsoNormal"><span style="font-family: Wingdings;" lang="EN-US"><span>l<span style="font: 7.0pt ;">  </span></span></span><span>如果两个操作数引用同一个对象</span><span lang="EN-US">(</span><span>数组,函数</span><span lang="EN-US">)</span><span>,则两者完全等同,否则不等同</span></p>
<p class="MsoNormal"><span style="font-family: Wingdings;" lang="EN-US"><span>l<span style="font: 7.0pt ;">  </span></span></span><span>如果两个操作数均为</span><span lang="EN-US">null/undefined</span><span>,则等同,否则不等同</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal"><span>比如:</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #7f0055; font-size: small;"><span style="font-size: 13px;"><strong>
</strong></span></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">var obj = {
    id : "self",
    name : "object"
};

var oa = obj;
var ob = obj;

print(oa == ob);
print(oa === ob);</pre>
 </strong>
<p> </p>
<p> </p>
<p class="MsoNormal"><span style="font-size: 10.0pt;" lang="EN-US"> </span></p>
<p class="MsoNormal"><span>会返回:</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #7f0055; font-size: small;"><span style="font-size: 13px;"><strong>
</strong></span></span></p>
<p><strong>
</strong></p>
<strong>
<div class="quote_div">true<br>true</div>
 </strong>
<p> </p>
<p> </p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal"><span>再来看一个对象的例子:</span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><strong><span style="font-size: 10.0pt;" lang="EN-US"> </span></strong></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #7f0055; font-size: small;"><span style="font-size: 13px;"><strong>
</strong></span></span></p>
<p><strong>
</strong></p>
<strong>
<pre name="code" class="js">var obj1 = {
    id : "self",
    name : "object",
    toString : function(){
       return "object 1";
    }
}

var obj2 = "object 1";

print(obj1 == obj2);
print(obj1 === obj2);</pre>
 </strong>
<p> </p>
<p> </p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal"><span>返回值为:</span></p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-align: left;" align="left"><span style="font-family: 'Courier New'; color: #7f0055; font-size: small;"><span style="font-size: 13px;"><strong>
</strong></span></span></p>
<p><strong>
</strong></p>
<strong>
<div class="quote_div">true<br>false</div>
 </strong>
<p> </p>
<p> </p>
<p class="MsoNormal"><span lang="EN-US"> </span></p>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span lang="EN-US">obj1</span><span>是一个对象,而</span><span lang="EN-US">obj2</span><span>是一个结构与之完全不同的字符串,而如果用相等操作符来判断,则两者是完全相同的,因为</span><span lang="EN-US">obj1</span><span>重载了顶层对象的</span><span lang="EN-US"><strong><em>toString()</em></strong></span><span>方法。</span></p>
<p class="MsoNormal" style="text-indent: 21.0pt;"><span>而</span><span lang="EN-US">!=</span><span>不等和</span><span lang="EN-US">!==</span><span>不等同,则与</span><span lang="EN-US">==/!==</span><span>相反。因此,在</span><span lang="EN-US">JavaScript</span><span>中,使用相等</span><span lang="EN-US">/</span><span>等同,不等</span><span lang="EN-US">/</span><span>不等同的时候,一定要注意类型的转换,这里<strong>推荐使用等同</strong></span><span lang="EN-US"><strong>/</strong></span><span><strong>不等同</strong>来进行判断,这样可以避免一些难以调试的</span><span lang="EN-US">bug</span><span>。</span></p>
<p> </p>
<p class="MsoNormal" style="text-indent: 21.0pt;"> </p>
<p class="MsoNormal" style="text-indent: 21.0pt;"> </p>
<p><span><strong style="font-weight: bold;">附:由于作者本身水平有限,文中难免有纰漏错误等,或者语言本身有不妥当之处,欢迎及时指正,提出建议,参与讨论,谢谢大家!</strong></span></p>
</div>
<p> </p>
26 楼 海阔天高 2010-04-08  
收藏下来慢慢看
期待下一章
25 楼 abruzzi 2010-04-08  
寻找出路的苍蝇 写道
对相等==运算符部分的论述有点疑
[quote]l  其中一个是true,先转换成1(false则转换为0)在做比较
这句话应该是真对一个操作数是true或false,另一个操作数是数字而言的。
对于一个操作数是布尔值、另一个操作数是字符串类型的相等运算,LZ最好也要说明下。这时在Firefox下,“1”为true,“”空字符串、“0”及其它字符串均为false,其它浏览器没有测试。
对于对象类型的操作数与原始类型的操作数作相等运算的情况,对象将通过valueOf()或toString()方法转化为原始类型然后再做比较,其中valueOf方法优先,LZ应该说明这个情况。


嗯,关于第一点,我是没有把前提条件描述清楚。
至于Firefox/其他浏览器对JS引擎实现上的差别,在目前的部分还不存在,因为还没有涉及到与浏览器相关的内容,因此叫“内核”,目前用的JS引擎为Rhino(是一个Java版的实现)。
valueOf()和toString()的优先问题,确实是我忽略掉了,谢谢你的提醒。

24 楼 寻找出路的苍蝇 2010-04-08  
对相等==运算符部分的论述有点疑
[quote]l  其中一个是true,先转换成1(false则转换为0)在做比较
这句话应该是真对一个操作数是true或false,另一个操作数是数字而言的。
对于一个操作数是布尔值、另一个操作数是字符串类型的相等运算,LZ最好也要说明下。这时在Firefox下,“1”为true,“”空字符串、“0”及其它字符串均为false,其它浏览器没有测试。
对于对象类型的操作数与原始类型的操作数作相等运算的情况,对象将通过valueOf()或toString()方法转化为原始类型然后再做比较,其中valueOf方法优先,LZ应该说明这个情况。
23 楼 jasonling168 2010-04-07  
非常不错的帖,很多时候人们都拼命的去学什么新的框架,新的开发包。往往会淡忘掉这些基础知识的重要性,这些都是砖,水泥,钢筋,水等等基础的材料啊。框架只是在这些基础上建出来的房子而已~~~

楼主继续更新~~~ 期待下期~
--Jason
22 楼 huazang_2010 2010-04-07  
我刚学习了
不是很懂。看的云里雾里的。

相关推荐

    javascript核心

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

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

    第2章 01 上节课复习 02 arp协议复习 03 字符编码 第3章 01 网络基础和dos命令 02 为何学习linux 03 课程内容介绍 04 操作系统内核与系统调用 05 操作系统安装原理 06 linux操作系统安装 07 初识linux命令 08 ...

    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 构建块 ...

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

    《C程序设计语言》(第2版新版)讲述深入浅出,配合典型例证,通俗易懂,实用性强,适合作为大专院校计算机专业或非计算机专业的C语言教材,也可以作为从事计算机相关软硬件开发的技术人员的参考书。《C程序设计语言》...

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

    第2章 Subversion中的增量编辑器:像本体一样的接口 2.1 版本控制与目录树的转换 2.2 表达目录树的差异 2.3 增量编辑器接口 2.4 但这是不是艺术? 2.5 像体育比赛一样的抽象 2.6 结论 第3章 我编写过的最漂亮代码 ...

    Tcl_TK编程权威指南pdf

    第2章 开始使用 source命令 unix上的tcl脚本程序 .windows 95的开始菜单 macintosh与resedit console命令 命令行变元 预定义变量 第3章 cgi应用程序--顾客留言簿 html简介 使用cgi创建动态页面 ...

    Android程序设计基础

    第2章回过头来介绍Android的基本概念和原理。第3章探讨用户界面,也就是大多数Android程序中最重要的部分。  致谢  我要感谢为本书成功出版做出贡献的许多人,包括审稿人Anthony Stevens、Gabor Paller、Fred ...

    ActionScript开发技术大全

    第2章搭建ActionScript3.0开发环境 9 2.1搭建基于FlashCS3IDE的开发环境 9 2.1.1安装FlashCS3ID 9 2.1.2安装FlashCS3IDEupdate9.0.2 11 2.1.3在FlashCS3IDE下创建ActionScript3.0项目 11 2.2搭建基于Flex的开发环境 ...

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

    第二章 多窗口类浏览器设计 11 2.1 多窗口类浏览器需求分析 11 2.1.1 Activity简介 11 2.1.2 Fragment简介 11 2.1.3 多窗口类浏览器需求 12 2.2 多窗口浏览器模式的实现机制 12 2.2.1安卓移动端多窗口浏览器框架 12 ...

Global site tag (gtag.js) - Google Analytics