编写高质量代码改善JavaScript程序的188个建议(1-78).docx
第1章 JavaScript语言基础对于任何语言来说,如何选用代码的写法和算法最终会影响到执行效率。与其他语言不同,由于JavaScript 可用资源有限,所以规范和优化更为重要。代码结构是执行速度的决定因素之一:代码量少,运行速度不一定快;代码量多,运行速度也不一定慢。性能损失与代码的组织方式及具体问题的解决办法直接相关。程序通常由很多部分组成,具体表现为函数、语句和表达式,它们必须准确无误地按照顺序排列。优秀的程序应该拥有前瞻性的结构,可以预见到未来所需要的修改。优秀的程序也有一种清晰的表达方式。如果一个程序被表达得很好,那么它更容易被理解,进而能够成功地被修改或修复。JavaScript代码经常被直接发布,因此它应该自始至终具备发布质量。整洁是会带来价值的,通过在一个清晰且始终如一的风格下编写的程序会更易于阅读。JavaScript的弱类型和过度宽容特征,没有为程序质量带来安全编译时的保证,为了弥补这一点,我们应该按严格的规范进行编码。JavaScript包含大量脆弱的或有问题的特性,这些会妨碍编写优秀的程序。我们应该避免JavaScript中那些糟糕的特性,还应该避免那些通常很有用但偶尔有害的特性。这样的特性让人既爱又恨,避免它们就能避免日后开发中潜在的错误。建议1:警惕Unicode乱码ECMA标准规定JavaScript语言基于Unicode标准进行开发,JavaScript内核完全采用UCS字符集进行编写,因此在JavaScript代码中每个字符都使用两个字节来表示,这意味着可以使用中文来命名变量或函数名,例如:1. var 人名 = "张三" 2. function 睡觉(谁) 3. alert(谁 + ":快睡觉!都半夜三更了。"); 4. 5. 睡觉(人名); 虽然ECMAScript v3标准允许Unicode字符出现在JavaScript程序的任何地方,但是在v1和v2中,ECMA标准只允许Unicode字符出现在注释或引号包含的字符串直接量中,在其他地方必须使用ASCII字符集,在ECMAScript标准化之前,JavaScript通常是不支持Unicode编码的。考虑到JavaScript版本的兼容性及开发习惯,不建议使用汉字来命名变量或函数名。由于JavaScript脚本一般都“寄宿”在网页中,并最终由浏览器来解析和执行,因此在考虑到JavaScript语言编码的同时,还要顾及嵌入页面的字符编码,以及浏览器支持的编码。不过现在的浏览器一般都支持不同类型的字符集,只需要考虑页面字符编码与JavaScript语言编码一致即可,否则就会出现乱码现象。当初设计JavaScript时,预计最多会有 65 536个字符,从那以后慢慢增长到了一百万个字符。JavaScript字符是16位的,这足够覆盖原有的65 536个字符,剩下的百万字符中的每一个都可以用一对字符来表示。Unicode把一对字符视为一个单一的字符,而JavaScript认为一对字符是两个不同的字符,这将会带来很多问题,考虑到代码的安全性,我们应该尽量使用基本字符进行编码。建议2:正确辨析JavaScript句法中的词、句和段JavaScript语法包含了合法的JavaScript代码的所有规则和特征,它主要分为词法和句法。词法包括字符编码、名词规则、特殊词规则等。词法侧重语言的底层实现(如语言编码问题等),以及基本规则的定义(如标识符、关键字、注释等)。它们都不是最小的语义单位,却是构成语义单位的组成要素。例如,规范字符编码集合、命名规则、标识符、关键字、注释规则、特殊字符用法等。句法定义了语言的逻辑和结构,包括词、句和段的语法特性,其中段体现逻辑的结构,句表达可执行的命令,词演绎逻辑的精髓。段落使用完整的结构封装独立的逻辑。在JavaScript程序中,常用大括号来划分结构,大括号拥有封装代码和逻辑的功能,由此形成一个独立的段落结构。例如,下面这些结构都可以形成独立的段落。1. 2. / 对象 3. 4. function () 5. / 函数 6. 7. if () 8. / 条件 9. 10. for () 11. / 循环 12. 13. while () 14. / 循环 15. 16. switch () 17. / 多条件 18. 19. with () 20. / 作用域 21. 22. try 23. / 异常处理 24. 段落结构包含的内容可以是一条或多条语句。可以在段落起始标记()前面添加修饰词,如域谓词(with、catch)、逻辑谓词(if、while、for、switch等)、函数谓词(function fn(arg))等。语句是由多个词构成的完整逻辑。在JavaScript中,常用分号(;)来划分语句,有时也可以省略分号,默认使用换行符表示完整的语句。一条语句可以包含一个或多个词。例如,在下面两条语句中,第一条语句只有一个词,这是一个指令词,该指令只能位于循环体或switch结构体内。第二条语句包含3个词,alert表示函数名(即变量),小括号表示运算符,而“"提示信息"”表示字符串直接量。1. break; 2. alert("提示信息"); 一条语句也可以包含一个或多个段落。例如,在下面这条语句中,直接把一个函数当做一个变量进行调用。1. (function(i) 2. alert(i); 3. )("提示信息"); 还可以把函数包含在一个闭包中形成多个结构嵌套,这个嵌套结构体就构成了一个复杂的语句,例如:1. (function(i) 2. return function() 3. alert(i); 4. 5. )("提示信息")(); 语句一般至少包含一个词或段落,但是语句也可以什么都不包含,仅由一个分号进行标识,这样的句子称为空语句。空语句常用做占位符。例如,在下面这个循环体内就包含了一个空语句。 1. for(var i; i<100;i+) 2. 3. 词语是JavaScript句法结构中的最小语义单位,包括指令(或称语句)、变量、直接量(或常量)、运算符等。在JavaScript中,词语之间必须使用分隔符进行分隔,否则JavaScript就会错误解析。下面的代码块是一个简单的求两个数平均值的方法。1. var a = 34; 2. var b = 56; 3. function aver(c,d) 4. return (c+d)/2; 5. 6. alert(aver(a,b); 其中var、function、return是指令,这些指令也是JavaScript默认的关键字;a、b、c、d、aver、alert为变量;34、56是数值直接量;=、(、)、/、+、,是运算符。建议3:减少全局变量污染定义全局变量有3种方式:在任何函数外面直接执行var语句。1. var f = 'value' 直接添加一个属性到全局对象上。全局对象是所有全局变量的容器。在Web浏览器中,全局对象名为window。 1. window.f = 'value' 直接使用未经声明的变量,以这种方式定义的全局变量被称为隐式的全局变量。 1. f = 'value' 为方便初学者在使用前无须声明变量而有意设计了隐式的全局变量,然而不幸的是忘记声明变量成了一个非常普遍的现象。JavaScript的策略是让那些被忘记预先声明的变量成为全局变量,这导致在程序中查找Bug变得非常困难。JavaScript语言最为糟糕的就是它对全局变量的依赖性。全局变量就是在所有作用域中都可见的变量。全局变量在很小的程序中可能会带来方便,但随着程序越来越大,它很快变得难以处理。因为一个全局变量可以被程序的任何部分在任意时间改变,使得程序的行为被极大地复杂化。在程序中使用全局变量降低了程序的可靠性。全局变量使在同一个程序中运行独立的子程序变得更难。如果某些全局变量的名称与子程序中的变量名称相同,那么它们将会相互冲突并可能导致程序无法运行,而且通常还使程序难以调试。实际上,这些全局变量削弱了程序的灵活性,应该避免使用全局变量。努力减少使用全局变量的方法:在应用程序中创建唯一一个全局变量,并定义该变量为当前应用的容器。1. var My = 2. My.name = 3. "first-name" : " first ", 4. "last-name" : " last " 5. ; 6. My.work = 7. number : 123, 8. one : 9. name : " one ", 10. time : "2012-9-14 12:55", 11. city : "beijing" 12. , 13. two : 14. name : "two", 15. time : "2012-9-12 12:42", 16. city : "shanghai" 17. 18. ; 只要把多个全局变量都追加在一个名称空间下,将显著降低与其他应用程序产生冲突的概率,应用程序也会变得更容易阅读,因为My.work指向的是顶层结构。当然也可以使用闭包体将信息隐藏,它是另一种有效减少“全局污染”的方法。在编程语言中,作用域控制着变量与参数的可见性及生命周期。这为程序开发提供了一个重要的帮助,因为它减少了名称冲突,并且提供了自动内存管理。1. var foo = function() 2. var a = 1, b = 2; 3. var bar = function() 4. var b = 3, c = 4; / a=1, b =3, c=4 5. a += b + c; / a=8, b =3, c=4 6. / a=1, b =2, c=undefined 7. bar(); / a=21, b =2, c=undefined 8. ; 大多数采用C语言语法的语言都拥有块级作用域。对于一个代码块,即包括在一对大括号中的语句,其中定义的所有变量在代码块的外部是不可见的。定义在代码块中的变量在代码块执行结束后会被释放掉。但是,对于JavaScript语言来说,虽然该语言支持代码块的语法形式,但是它并不支持块级作用域。JavaScript支持函数作用域,定义在函数中的参数和变量在函数外部是不可见的,并且在一个函数中的任何位置定义的变量在该函数中的任何地方都可见。其他主流编程语言都推荐尽可能迟地声明变量,但是在JavaScript中就不能够这样,因为它缺少块级作用域,最好的做法是在函数体的顶部声明函数中可能用到的所有变量。建议4:注意JavaScript数据类型的特殊性(1)1.防止浮点数溢出二进制的浮点数不能正确地处理十进制的小数,因此0.1+0.2不等于0.3。1. num = 0.1+0.2; /0.30000000000000004 这是JavaScript中最经常报告的Bug,并且这是遵循二进制浮点数算术标准(IEEE 754)而导致的结果。这个标准适合很多应用,但它违背了数字基本常识。幸运的是,浮点数中的整数运算是精确的,所以小数表现出来的问题可以通过指定精度来避免。例如,针对上面的相加可以这样进行处理:1. a = (1+2)/10; /0.3 这种处理经常在货币计算中用到,在计算货币时当然期望得到精确的结果。例如,元可以通过乘以100而全部转成分,然后就可以准确地将每项相加,求和后的结果可以除以100转换回元。2.慎用JavaScript类型自动转换在JavaScript中能够自动转换变量的数据类型,这种转换是一种隐性行为。在自动转换数据类型时,JavaScript一般遵循:如果某个类型的值被用于需要其他类型的值的环境中,JavaScript就自动将这个值转换成所需要的类型,具体说明见表1.1。表1.1数据类型自动转换 (续) 如果把非空对象用在逻辑运算环境中,则对象被转换为true。此时的对象包括所有类型的对象,即使是值为false的包装对象也被转换为true。如果把对象用在数值运算环境中,则对象会被自动转换为数字,如果转换失败,则返回值为NaN。当数组被用在数值运算环境中时,数组将根据包含的元素来决定转换的值。如果数组为空数组,则被转换为数值0。如果数组仅包含一个数字元素,则被转换为该数字的数值。如果数组包含多个元素,或者仅包含一个非数字元素,则返回NaN。当对象用于字符串环境中时,JavaScript能够调用toString()方法把对象转换为字符串再进行相关计算。当对象与数值进行加号运算时,则会尝试将对象转换为数值,然后参与求和运算。如果不能够将对象转换为有效数值,则执行字符串连接操作。建议4:注意JavaScript数据类型的特殊性(2)3.正确检测数据类型使用typeof运算符返回一个用于识别其运算数类型的字符串。对于任何变量来说,使用typeof运算符总是以字符串的形式返回以下6种类型之一:"number""string""boolean""object""function""undefined"不幸的是,在使用typeof检测null值时,返回的是“object”,而不是“null”。更好的检测null的方式其实很简单。下面定义一个检测值类型的一般方法:1. function type(o) 2. return (o = null) ? "null" : (typeof o); 3. 这样就可以避开因为null值影响基本数据的类型检测。注意:typeof不能够检测复杂的数据类型,以及各种特殊用途的对象,如正则表达式对象、日期对象、数学对象等。对于对象或数组,可以使用constructor属性,该属性值引用的是原来构造该对象的函数。如果结合typeof运算符和constructor属性,基本能够完成数据类型的检测。表1.2所示列举了不同类型数据的检测结果。表1.2数据类型检测 使用constructor属性可以判断绝大部分数据的类型。但是,对于undefined和null特殊值,就不能使用constructor属性,因为使用JavaScript解释器会抛出异常。此时可以先把值转换为布尔值,如果为true,则说明不是undefined和null值,然后再调用constructor属性,例如:1. var value = undefined; 2. alert(typeof value); /"undefined" 3. alert(value && value.constructor); /undefined 4. var value = null; 5. alert(typeof value); /"object" 6. alert(value && value.constructor); /null 对于数值直接量,也不能使用constructor属性,需要加上一个小括号,这是因为小括号运算符能够把数值转换为对象,例如:1. alert(10).constructor); 使用toString()方法检测对象类型是最安全、最准确的。调用toString()方法把对象转换为字符串,然后通过检测字符串中是否包含数组所特有的标志字符可以确定对象的类型。toString()方法返回的字符串形式如下: 1. object class 建议4:注意JavaScript数据类型的特殊性(3)其中,object表示对象的通用类型,class表示对象的内部类型,内部类型的名称与该对象的构造函数名对应。例如,Array对象的class为“Array”,Function对象的class为“Function”,Date对象的class为“Date”,内部Math对象的class为“Math”,所有Error对象(包括各种Error子类的实例)的class为“Error”。客户端JavaScript的对象和由JavaScript实现定义的其他所有对象都具有预定义的特定class值,如“Window”、“Document”和“Form”等。用户自定义对象的class值为“Object”。class值提供的信息与对象的constructor属性值相似,但是class值是以字符串的形式提供这些信息的,而不是以构造函数的形式提供这些信息的,所以在特定的环境中是非常有用的。如果使用typeof运算符来检测,则所有对象的class值都为“Object”或“Function”,所以此时的class值不能够提供有效信息。但是,要获取对象的class值的唯一方法是必须调用Object对象定义的默认toString()方法,因为不同对象都会预定义自己的toString()方法,所以不能直接调用对象的toString()方法。例如,下面对象的toString()方法返回的就是当前UTC时间字符串,而不是字符串“object Date”。1. var d = new Date(); 2. alert(d.toString(); /当前UTC时间字符串 要调用Object对象定义的默认toString()方法,可以先调用Object.prototype.toString对象的默认toString()函数,再调用该函数的apply()方法在想要检测的对象上执行。结合上面的对象d,具体实现代码如下: 1. var d = new Date(); 2. var m = Object.prototype.toString; 3. alert(m.apply(d); /" object Date " 下面是一个比较完整的数据类型安全检测方法。1. / 安全检测JavaScript基本数据类型和内置对象 2. / 参数:o表示检测的值 3. /* 返回值:返回字符串"undefined"、"number"、"boolean"、"string"、"function"、"regexp"、"array"、"date"、"error"、"object"或"null" */ 4. function typeOf(o) 5. var _toString = Object.prototype.toString; 6. / 获取对象的toString()方法引用 7. / 列举基本数据类型和内置对象类型,可以进一步补充该数组的检测数据类型范围 8. var _type = 9. "undefined" : "undefined", 10. "number" : "number", 11. "boolean" : "boolean", 12. "string" : "string", 13. "object Function" : "function", 14. "object RegExp" : "regexp", 15. "object Array" : "array", 16. "object Date" : "date", 17. "object Error" : "error" 18. 19. return _typetypeof o | _type_toString.call(o) | (o ? "object" : "null"); 20. 应用示例:1. var a = Math.abs; 2. alert(typeOf(a); /"function" 上述方法适用于JavaScript基本数据类型和内置对象,而对于自定义对象是无效的。这是因为自定义对象被转换为字符串后,返回的值是没有规律的,并且不同浏览器的返回值也是不同的。因此,要检测非内置对象,只能够使用constructor属性和instaceof运算符来实现。建议4:注意JavaScript数据类型的特殊性(4)4.避免误用parseIntparseInt是一个将字符串转换为整数的函数,与parseFloat(将字符串转换为浮点数)对应,这两种函数是JavaScript提供的两种静态函数,用于把非数字的原始值转换为数字。 在开始转换时,parseInt会先查看位置0处的字符,如果该位置不是有效数字,则将返回NaN,不再深入分析。如果位置0处的字符是数字,则将查看位置1处的字符,并重复前面的测试,依此类推,直到发现非数字字符为止,此时parseInt()函数将把前面分析合法的数字字符转换为数值并返回。1. parseInt("123abc"); / 123 2. parseInt("1.73"); / 1 3. parseInt(".123"); / NaN 浮点数中的点号对于parseInt来说属于非法字符,因此它不会被转换并返回,这样,在使用parseInt时,就存在潜在的误用风险。例如,我们并不希望parseInt("16")与parseInt("16 tons")产生相同的结果。如果该函数能够提醒我们出现额外文本就好了,但它不会那么做。对于以0为开头的数字字符串,parseInt()函数会把它作为八进制数字处理,先把它转换为数值,然后再转换为十进制的数字返回。对于以0x开头的数字字符串, parseInt()函数则会把它作为十六进制数字处理,先把它转换为数值,然后再转换为十进制的数字返回。例如:1. var d = "010" /八进制 2. var e = "0x10" /十六进制 3. parseInt(d); /8 4. parseInt(e); /16 如果字符串的第一个字符是0,那么该字符串将基于八进制而不是十进制来求值。在八进制中,8和9不是数字,所以parseInt("08")和parseInt("09")的结果为0,这个错误导致了在程序解析日期和时间时经常会出现问题。幸运的是,parseInt可以接受一个基数作为参数,这样parseInt("08",10)结果为8,parseInt("09",10)结果为9。因此,建议读者在使用parseInt时,一定要提供这个基数参数。通过在parseInt中提供基数参数,可以把二进制、八进制、十六进制等不同进制的数字字符串转换为整数。例如,下面把十六进制数字字符串"123abc"转换为十进制整数。1. parseInt("123abc",16); / 1194684 再如,把二进制、八进制和十进制数字字符串转换为整数:1. parseInt("10",2); /把二进制数字10转换为十进制整数为2 2. parseInt("10",8); /把八进制数字10转换为十进制整数为8 3. parseInt("10" ,10); /把十进制数字10转换为十进制整数为10 建议5:防止JavaScript自动插入分号JavaScript语言有一个机制:在解析时,能够在一句话后面自动插入一个分号,用来修改语句末尾遗漏的分号分隔符。然而,由于这个自动插入的分号与JavaScript语言的另一个机制发生了冲突,即所有空格符都被忽略,因此程序可以利用空格格式化代码。这两种机制的冲突,很容易掩盖更为严重的解析错误。有时会不合时宜地插入分号。例如,在return语句中自动插入分号将会导致这样的后果:如果return语句要返回一个值,这个值的表达式的开始部分必须和return在同一行上,例如:1. var f = function() 2. return 3. 4. status: true 5. 6. 看起来这里要返回一个包含status成员元素的对象。不幸的是,JavaScript自动插入分号让它返回了undefined,从而导致下面真正要返回的对象被忽略。当自动插入分号导致程序被误解时,并不会有任何警告提醒。如果把放在上一行的尾部而不是下一行的头部,就可以避免该问题,例如:1. var f = function() 2. return 3. status: true 4. 5. 为了避免省略分号引起的错误,建议养成好的习惯,不管一行内语句是否完整,只要是完整的语句都必须增加分号以表示句子结束。为了方便阅读,当长句子需要分行显示时,在分行时应确保一行内不能形成完整的逻辑语义。例如,下面代码是一条连续赋值的语句,通过分行显示可以更清楚地查看它们的关系。这种分行显示,由于一行内不能形成独立的逻辑语义,因此JavaScript不会把每一行视为独立的句子,从而不会产生歧义。1. var a = 2. b = 3. c = 4; 以上语句在一行内显示如下: 1. var a = b = c = 4; 对于下面这条语句,如果不能正确分行显示,就很容易产生歧义。该句子的含义:定义一个变量i,然后为其赋值,如果变量a为true,则赋值为1,否则就判断变量b,如果b为true,则赋值为2,否则就判断变量c,如果c为true,则赋值为3,否则赋值为4。 1. var i = a ? 1 : b ? 2 : c ? 3 : 4; 下面的分行显示就是错误的,因为表达式a ? 1: b能够形成独立的逻辑语义,所以JavaScript会自动在其后添加分号来表示一个独立的句子。1. var i = a ? 1: b 2. ? 2 : c 3. ? 3 : 4; 安全的方法应该采用如下的分行显示,这样每一行都不能形成独立的语义。 1. var i = a ? 1 2. : b ? 2 3. : c ? 3 4. : 4; 总之,在编写代码时,应养成使用分号结束句子的良好习惯,凡是完整的句子就应该使用分号进行分隔。分行显示的句子应该确保单行不容易形成独立的合法的逻辑语义。建议6:正确处理JavaScript特殊值(1)1.正确使用NaN和InfinityNaN是IEEE 754中定义的一个特殊的数量值。它不表示一个数字,尽管下面的表达式返回的是true。1. typeof NaN = 'number' / true 该值可能会在试图将非数字形式的字符串转换为数字时产生,例如:1. + '0' / 0 2. + 'oops' / NaN 如果NaN是数学运算中的一个运算数,那么它与其他运算数的运算结果就会是NaN。如果有一个表达式产生出NaN的结果,那么至少其中一个运算数是NaN,或者在某个地方产生了NaN。可以对NaN进行检测,但是typeof不能辨别数字和NaN的区别,并且NaN不等同于它自己,所以,下面的代码结果令人惊讶。1. NaN = NaN / false 2. NaN != NaN / true 为了方便检测NaN值,JavaScript提供isNaN静态函数,以辨别数字与NaN区别。 1. isNaN(NaN) / true 2. isNaN(0) / false 3. isNaN('oops') / true 4. isNaN('0') / false 判断一个值是否可用做数字的最佳方法是使用isFinite函数,因为它会筛除掉NaN和Infinity。Infinity表示无穷大。当数值超过浮点数所能够表示的范围时,就要用Infinity表示。反之,负无穷大为Infinity。使用isFinite函数能够检测NaN、正负无穷大。如果是有限数值,或者可以转换为有限数值,那么将返回true。如果只是NaN、正负无穷大的数值,则返回false。不幸的是,isFinite会试图把它的运算数转换为一个数字。因此,如果值不是一个数字,使用isFinite函数就不是一个有效的检测方法,这时不妨自定义isNumber函数。1. var isNumber = function isNumber(value) 2. return typeof value = 'number' && isFinite(value); 3. 2.正确使用null和undefinedJavaScript有5种基本类型:String、Number、Boolean、Null和Undefined。前3种都比较好理解,后面两种就稍微复杂一点。Null 类型只有一个值,就是null;Undefined类型也只有一个值,即undefined。 null 和undefined都可以作为字面量在 JavaScript 代码中直接使用。null与对象引用有关系,表示为空或不存在的对象引用。当声明一个变量却没有向它赋值的时候,它的值就是undefined。undefined的值会在如下情况中出现:从一个对象中获取某个属性,如果该对象及其prototype链中的对象都没有该属性,该属性的值为undefined。一个函数如果没有显式通过return语句将返回值返回给其调用者,其返回值就是undefined,但在使用new调用函数时例外。JavaScript的函数可以声明任意多个形参,当该函数实际被调用时,传入的参数的个数如果小于声明的形式参数的个数,那么多余的形式参数的值为undefined。如果对值为null的变量使用typeof检测,得到的结果是“object”,而typeof undefined的值为“undefined”。null = undefined, null != undefined。建议6:正确处理JavaScript特殊值(2)与null不同,undefined不是JavaScript的保留字,在ECMAScript v3标准中才定义undefined为全局变量,初始值为undefined。因此,在使用undefined值时就存在一个兼容问题(早期浏览器可能不支持undefined)。除了直接赋值和使用typeof运算符外,其他任何运算符对undefined的操作都会引发异常。不过,可以声明undefined变量,然后查看它的值,如果它的值为undefined,则说明浏览器支持undefined值。例如:1. var undefined; 2. alert(undefined); 如果浏览器不支持undefined关键字,可以自定义undefined变量,并将其赋值为undefined。例如: 1. var undefined = void null; 声明变量为undefined,将其初始化为表达式void null的值,由于运算符void在执行其后的表达式时会忽略表达式的结果值,而总是返回值undefined,因此利用这种方法可以定义一个变量为undefined,并将其赋值为undefined。既然是将变量undefined赋值为undefined,还可以使用如下方式:1. var undefined = void 1; 或者使用没有返回值的函数:1. var undefined = function()(); 2. alert(undefined); /"undefined" 可以使用typeof运算符来检测某个变量的值是否为undefined:1. var a; 2. if(typeof a = "undefined") 3. 3.使用假值JavaScript的类型系统是非常混乱的,类型特性不明显,而且交叉错乱。JavaScript语法系统拥有一大组假值,如以下代码所示。这些值的布尔值都是false。1. 0 /Number 2. NaN /Number 3. '' /String 4. false /Boolean 5. null /Object 6. undefined /Undefined 这些值全部都等同于false,但它们是不可互换的。例如,下面用法是错误的。 1. value = myObjectname; 2. if(value = null) 3. 这是在用一种错误的方式去确定一个对象是否缺少一个成员属性。undefined是缺失的成员属性值,而上面代码片段用null来测试,使用了会强制类型转换的=运算符,而不是更可靠的=运算符。正确的用法如下: 1. value = myObjectname; 2. if(!value) 3. undefined和NaN并不是常见,它们是全局变量,还可以改变它们的值,虽然在程序设计中不应该采取这种做法,但可以改变它们的值。建议7:小心保留字的误用JavaScript语言中定义了很多备用或已经使用的保留字,按首字母顺序列出的保留字见表1.3。表1.3JavaScript语言中定义的保留字 这些单词中的大多数并没有在语言中使用,但是根据JavaScript语法规则,这些单词是不能用来命名变量或参数的。当保留字作为对象字面量的