ECMAScript 5 最先引入了“严格模式”(strict mode)的概念。经过严格模式,能够在函数内部编程
选择进行较为严格的全局或局部的错误条件检测。使用严格模式的好处是能够提前知道代码中浏览器
存在的错误,及时捕获一些可能致使编程错误的ECMAScript 行为。安全
理解严格模式的规则很是重要,ECMAScript 的下一个版本将以严格模式为基础制定。支持严格模app
式的浏览器包括IE10+、Firefox 4+、Safari 5.1+和Chrome。函数
1.选择使用测试
要选择进入严格模式,可使用严格模式的编译指示(pragma),实际上就是一个不会赋给任何变this
量的字符串:spa
"use strict";code
这种语法(从ECMAScript 3 开始支持)能够向后兼容那些不支持严格模式的JavaScript 引擎。支持orm
严格模式的引擎会启动这种模式,而不支持该模式的引擎就当遇到了一个未赋值的字符串字面量,会忽
略这个编译指示。
若是是在全局做用域中(函数外部)给出这个编译指示,则整个脚本都将使用严格模式。换句话说,
若是把带有这个编译指示的脚本放到其余文件中,则该文件中的JavaScript 代码也将处于严格模式下。
也能够只在函数中打开严格模式,就像下面这样:
function doSomething(){"use strict";//其余代码}
若是你没有控制页面中全部脚本的权力,建议只在须要测试的特定函数中开启严格模式。
2 .变量
在严格模式下,何时建立变量以及怎么建立变量都是有限制的。首先,不容许意外建立全局变
量。在非严格模式下,能够像下面这样建立全局变量:
//未声明变量//非严格模式:建立全局变量//严格模式:抛出ReferenceErrormessage = "Hello world! ";
即便message 前面没有var 关键字,即便没有将它定义为某个全局对象的属性,也能将message
建立为全局变量。但在严格模式下,若是给一个没有声明的变量赋值,那代码在执行时就会抛出
ReferenceError。
其次,不能对变量调用delete 操做符。非严格模式容许这样操做,但会静默失败(返回false)。
而在严格模式下,删除变量也会致使错误。
//删除变量//非严格模式:静默失败//严格模式:抛出ReferenceErrorvar color = "red";delete color;
严格模式下对变量名也有限制。特别地,不能使用implements、interface、let、package、
private、protected、public、static 和yield 做为变量名。这些都是保留字,未来的ECMAScript
版本中可能会用到它们。在严格模式下,用以上标识符做为变量名会致使语法错误。
3.对象
在严格模式下操做对象比在非严格模式下更容易致使错误。通常来讲,非严格模式下会静默失败的
情形,在严格模式下就会抛出错误。所以,在开发中使用严格模式会加大早发现错误的可能性。
在下列情形下操做对象的属性会致使错误:
为只读属性赋值会抛出TypeError;
对不可配置的(nonconfigurable)的属性使用delete 操做符会抛出TypeError;
为不可扩展的(nonextensible)的对象添加属性会抛出TypeError。
使用对象的另外一个限制与经过对象字面量声明对象有关。在使用对象字面量时,属性名必须惟一。
例如:
//重名属性//非严格模式:没有错误,以第二个属性为准//严格模式:抛出语法错误var person = { name: "Nicholas", name: "Greg"};
这里的对象person 有两个属性,都叫name。在非严格模式下,person 对象的name 属性值是第
二个,而在严格模式下,这样的代码会致使语法错误。
4.函数
首先,严格模式要求命名函数的参数必须惟一。如下面这个函数为例:
//重名参数//非严格模式:没有错误,只能访问第二个参数//严格模式:抛出语法错误function sum (num, num){//do something}
在非严格模式下,这个函数声明不会抛出错误。经过参数名只能访问第二个参数,要访问第一个参
数必须经过arguments 对象。
在严格模式下,arguments 对象的行为也有所不一样。在非严格模式下,修改命名参数的值也会反
映到arguments 对象中,而严格模式下这两个值是彻底独立的。例如:
//修改命名参数的值//非严格模式:修改会反映到arguments 中//严格模式:修改不会反映到arguments 中function showValue(value){ value = "Foo"; alert(value); //"Foo"alert(arguments[0]); //非严格模式:"Foo"//严格模式:"Hi"} showValue("Hi");
以上代码中,函数showValue()只有一个命名参数value。调用这个函数时传入了一个参数"Hi",
这个值赋给了value。而在函数内部,value 被改成"Foo"。在非严格模式下,这个修改也会改变
arguments[0]的值,但在严格模式下,arguments[0]的值仍然是传入的值。
另外一个变化是淘汰了arguments.callee 和arguments.caller。在非严格模式下,这两个属
性一个引用函数自己,一个引用调用函数。而在严格模式下,访问哪一个属性都会抛出TypeError。
例如:
//访问arguments.callee//非严格模式:没有问题//严格模式:抛出TypeErrorfunction factorial(num){if (num <= 1) {return 1; } else {return num * arguments.callee(num-1) } }var result=factorial(5);
相似地,尝试读写函数的caller 属性,也会致使抛出TypeError。因此,对于上面的例子而言,
访问factorial.caller 也会抛出错误。
与变量相似,严格模式对函数名也作出了限制,不容许用implements、interface、let、package、
private、protected、public、static 和yield 做为函数名。
对函数的最后一点限制,就是只能在脚本的顶级和在函数内部声明函数。也就是说,在if 语句中
声明函数会致使语法错误:
//在if 语句中声明函数//非严格模式:将函数提高到if 语句外部//严格模式:抛出语法错误if (true){function doSomething(){//...} }
在非严格模式下,以上代码能在全部浏览器中运行,但在严格模式下会致使语法错误。
5.eval()
饱受诟病的eval()函数在严格模式下也获得了提高。最大的变化就是它在包含上下文中再也不建立
变量或函数。例如:
//使用eval()建立变量//非严格模式:弹出对话框显示10//严格模式:调用alert(x)时会抛出ReferenceErrorfunction doSomething(){ eval("var x=10"); alert(x); }
若是是在非严格模式下,以上代码会在函数doSomething()中建立一个局部变量x,而后alert()
还会显示该变量的值。但在严格模式下,在doSomething()函数中调用eval()不会建立变量x,所以
调用alert()会致使抛出ReferenceError,由于x 没有定义。
能够在eval()中声明变量和函数,但这些变量或函数只能在被求值的特殊做用域中有效,随后就
将被销毁。所以,如下代码能够运行,没有问题:
"use strict";var result = eval("var x=10, y=11; x+y"); alert(result); //21
这里在eval()中声明了变量x 和y,而后将它们加在一块儿,返回了它们的和。因而,result 变
量的值是21,即x 和y 相加的结果。而在调用alert()时,尽管x 和y 已经不存在了,result 变量
的值仍然是有效的。
6.eval与arguments
严格模式已经明确禁止使用eval 和arguments 做为标识符,也不容许读写它们的值。例如:
//把eval 和arguments 做为变量引用//非严格模式:没问题,不出错//严格模式:抛出语法错误var eval = 10;var arguments = "Hello world!";
在非严格模式下,能够重写eval,也能够给arguments 赋值。但在严格模式下,这样作会致使语
法错误。不能将它们用做标识符,意味着如下几种使用方式都会抛出语法错误:
使用var 声明;
赋予另外一个值;
尝试修改包含的值,如使用++;
用做函数名;
用做命名的函数参数;
在try-catch 语句中用做例外名。
7.抑制this
JavaScript 中一个最大的安全问题,也是最容易让人迷茫的地方,就是在某些状况下如何抑制this
的值。在非严格模式下使用函数的apply()或call()方法时,null 或undefined 值会被转换为全局
对象。而在严格模式下,函数的this 值始终是指定的值,不管指定的是什么值。例如:
//访问属性//非严格模式:访问全局属性//严格模式:抛出错误,由于this 的值为nullvar color = "red";function displayColor(){ alert(this.color); } displayColor.call(null);
以上代码向displayColor.call()中传入了null,若是在是非严格模式下,这意味着函数的this
值是全局对象。结果就是弹出对话框显示"red"。而在严格模式下,这个函数的this 的值是null,因
此在访问null 的属性时就会抛出错误。
8.其余变化
严格模式还有其余一些变化,但愿读者也能留意。首先是抛弃了with 语句。非严格模式下的with
语句可以改变解析标识符的路径,但在严格模式下,with 被简化掉了。所以,在严格模式下使用with
会致使语法错误。
//with 的语句用法//非严格模式:容许//严格模式:抛出语法错误with(location){ alert(href); }
严格模式也去掉了JavaScript 中的八进制字面量。以0 开头的八进制字面量过去常常会致使不少错
误。在严格模式下,八进制字面量已经成为无效的语法了。
//使用八进制字面量//非严格模式:值为8//严格模式:抛出语法错误var value = 010;
ECMAScript 5 也修改了严格模式下parseInt()的行为。现在,八进制字面量在
严格模式下会被看成以0 开头的十进制字面量。例如:
//使用parseInt()解析八进制字面量//非严格模式:值为8//严格模式:值为10var value = parseInt("010");