一、严格模式
2009年定稿的第5版ECMAScript标准(简称ES5)引入了一种版本控制的考量——严格模式(strict mode)。此特性允许你选择在受限制的JavaScript版本中禁止使用一些JavaScript语言中问题较多或易于出错的特性。由于其语法向后兼容,所以即使在没有严格模式检查的环境中也可以执行严格代码。在程序中启用严格模式的方式是在程序最开始增加一个特定的字符串字面量:"use strict";
或者也可在函数体的开始出加入这句话。
function f(x){
"use strict";
//...
}
严格模式代码可以运行在旧的JavaScript引擎上,但是如果没有在ES5的环境中做过测试,那么,编写的代码运行于ES5中就很容易出错。
function f(x){
"use strict";
var arguments = [];//error:redefinition of arguments
}
在严格模式下,不允许重新定义arguments变量,但没有实现严格模式检查的环境会接受这段代码。然而,这段代码部署在实现ES5的产品环境中将导致程序出错。
"use strict"指令只有在脚本或函数的顶部才能生效,这也是严格模式的一个陷阱。
例如,想将一个文件运行于严格模式下:
//file1.js
"use strict";
function f(){
//...
}
//...
而另一个文件不是运行于严格模式下:
//file2.js
//no strict-mode directive
function g(){
var arguments = [];
//...
}
//...
如果我们一file1.js文件开始,那么,连接后的代码全部运行在严格模式下;如果我们以file2文件开始,MAME连接后的代码运行于非严格模式下。
在自己的项目中,你可以坚持只使用“严格模式”或只使用“非严格模式”的策略,但如果你要编写健壮的代码应对各种各样的代码连接,有两个方案:
1.不要将进行严格模式检查的文件和不进行严格模式检查的文件连接:至少部署两个独立的文件,一个包含进行严格模式检查的文件,另一个包含不进行严格模式检查的文件。
2.通过将文件自身包裹在立即调用的函数表达式中的方式连接多个文件:将每个文件的内容包裹在一个立即调用的函数中,即使在不同的模式下,它们都将被独立地解释执行。
基于第二个方案,上面的例子连接版本如下:
//no strict-mode directive
(function(){
//file.js
"use strict";
funciton f(){
//...
}
//...
})();
(function(){
//file2.js
//no strict-mode directive
function g(){
var arguments = [];
//...
}
//...
})();
由于每个文件的内容被放置在一个单独的作用域中,所以使用严格模式指令只影响本文件的内容。
最后注意:即使一个函数没有选择严格模式,如果它连接在严格代码之后,它仍被视为是严格的。所以,为了达到更为普遍的兼容性,建议在严格模式下编写代码。
二、隐式的强制转换
JavaScript对类型错误很宽容,大多数情况下,JavaScript不会抛出一个错误,而是按照多种多样的自动转换协议将值强制转换为期望的类型。例如,算术运算符-、*、/和%在计算之前都会尝试将其参数转换为数字。
位运算符不仅会将操作数转换为数字,而且还会将操作数转换为32位整数(表示的数字的子集)。这些运算符包括算术运算符(~、&、^和|)以及移位运算符(<<、>>和>>>)。
强制转换中结果为null的变量在算术运算中会被隐式地转换为0;一个未定义的变量将会被转换为特殊的浮点数值NaN。
NaN不等于其本身,因此:
var x = NaN;
x === NaN;//false
而且,标准库函数isNaN也不可靠,它会将自己的参数先转换为数字再对其进行测试。
由于NaN是JavaScript中唯一一个不等于自身的值,要想判断一个值是否为NaN,最好通过以下方法:
var a = NaN;
a !== a;//true
真值运算:if、||和&&等运算符逻辑上需要布尔值作为操作参数,但实际上可以接受任何值。JavaScript按照简单的隐式强制转换规则将值解释为布尔值。大多数的JavaScript值都能隐式地转换为true,这些值被称为真值。但是JavaScript中有7个假值:false、0、-0、""、NaN、null和undefined。由于数字和字符串可能为假值,因此,使用真值运算检查函数参数或者对象属性是否定义不是绝对安全的。例如:
function poin(x,y){
if(!x){
x = 320;
}
if(!y){
y = 200;
}
return {x:x,y:y};
}
此函数忽略任何为假值得参数,包括0:
point(0,0)//{x:320,y:200}
检查参数是否为undefined更为严格的方式是使用typeof。
function point(x,y){
if(typeof x === "undefined"){
x = 320;
}
if(typeof y === "undefined"){
x = 200;
}
return {x:x,y:y};
}
此时point函数可以正确的识别0和undefined。
point();//{x:320,y:200}
point(0,0);//{x:0,y:0}