在严格模式下,能够在函数内部选择进行较为严格的全局或局部的错误条件检测。使用严格模式的好处是可以提早知道代码中存在的错误,即使捕获一些可能导致编程uowu的ECMAScript行为。
理解严格模式的规范非常重要,ECMAScript的下一个版本将以严格模式为基础指定。支持严格模式的浏览器包括IE10+,Firefox4+, Safari5.1+和Chrome。
1. 选择使用 #
要选择进入严格模式,可以使用严格模式的编译指示,实际上就是一个不会赋给任何变量的字符串:
use strict;
在老版本的浏览器里,会把它当做一行普通的字符串,加以葫芦。
如果在全局作用域中(函数外部)给出这个编译知识,则整个脚本都将使用严格模式。换句话说,如果把带有这个编译指示的脚本放到其他文件中,则该文件中的Javascript代码将处于严格模式下。
也可以只在函数中打开严格模式,就像下面这样:
function doSomething(){
"use strict";
// 其他代码
}
如果你没有控制页面中所有脚本的权利,建议只在需要测试的特定函数中开启严格模式。
2. 变量 #
在严格模式下,什么时候创建变量以及怎么创建变量都是有限制的。首先,不允许意外创建全局变量。在非严格模式下,可以像下面这样创建全局变量。
// 未声明变量
// 非严格模式:创建全局变量
// 严格模式:抛出错误
message = "hello wenzi";
即使message前面没有var关键字,即使没有将它定义为某个全局对象的属性,也能将message为全局变量。但在严格模式下,如果给一个没有声明的变量赋值,那代码在执行时就会抛出错误。
其实不能对变量调用delete操作符。非严格模式允许这样操作,单户静默失败(返回false),而在严格模式下,删除变量也会导致错误。
// 删除变量
// 非严格模式:静默失败
// 严格模式:抛出错误
var color = "red";
delete color;
严格模式下对变量名也有限制。特别地,不能使用implements
, interface
, protected
, public
, static
和yield
作为变量名。这些都是保留字,将来的ES版本中可能会使用到他们。在严格模式,用以上的标识符作为变量会导致语法错误。
3. 对象 #
在严格模式下操作对象比在非严格模式下更容易导致错误。一般来说,非严格模式下会静默失败的情形,在严格模式下就会抛出错误。因此在开发中使用严格模式更能发现错误。
在下列情形下操作对象的属性会导致错误:
- 为只读属性进行赋值;
- 为不可配置的属性使用delete操作符;
- 为不可扩展的对象添加谁能够 使用对象的另一个限制与通过对象字面量声明对象有关。在使用对象字面量时,属性名必须唯一。例如:
// 重名属性
// 非严格模式:没有错误,以第二个属性为准
// 严格模式:抛出语法错误
var student = {
name : 'wenzi',
name : 'bing'
}
这里的对象student有两个属性,都叫name。在非严格模式下,student对象的name属性值是第二个,而在严格模式下,这样的代码会导致语法错误。
4. 函数 #
首先,严格模式下要求明明函数的参数必须唯一。以下面这个函数为例:
// 重名参数
// 非严格模式:没有错误,只能访问第二个参数
// 严格模式:抛出语法错误
function doSomething(num, num){
// 其他代码
}
在非严格模式下,这个函数声明不会抛出错误。通过参数名只能访问第二个参数,要访问第一个参数必须通过arguments对象。
在严格模式下,arguments对象的行为也有所不同,在非严格模式下,修改明明参数的值也会反应到arguments对象中,而严格模式下这两个值是完全独立的。如:
// 修改命名参数的值
// 非严格模式:修改会反应到arguments中
// 严格模式:修改不会反应到arguments中
function doSomething(value){
value = 7;
console.log(value, arguments[0]);
// 非严格模式下,输出:7, 7
// 严格模式下,输出:7, 10
}
doSomething(10);
另一个变化是淘汰了arguments.callee和arguments.caller。在非严格模式下,这两个属性一个引用函数本身,一个引用调用函数。而在严格模式下,访问哪个属性都会抛出TypeError。例如:
// 访问arguments.callee
// 非严格模式:正常
// 严格模式:抛出错误
function factorial(num){
if(num<=) return 1;
return num*arguments.callee(num-1);
}
var result = factorial(4);
与变量类似,严格模式对函数名也作出了限制,不允许使用implements
, interface
, protected
, public
, static
和yield
作为函数名。
对函数的最后一点限制,就是只能在脚本的顶级和在函数内部声明函数。而在if语句中声明函数与导致语法错误:
if(true){
function doSomething(){
// ...
}
}
在非严格模式下,以上代码在所有的浏览器上都能运行;而严格模式下会导致语法错误。
5. eval() #
饱受诟病的eval()在严格模式下也得到了提升。最大的变化就是它在包含上下文中不再创建变量或函数。例如:
// 使用eval()创建变量
// 非严格模式:弹出对话框显示10
// 严格模式:抛出错误
function doSomething(){
eval("x=10");
alert(x);
}
如果在非严格模式下,以上代码在函数中会创建一个局部变量x,然后alert(),还会显示该变量的值。但在严格模式下,在doSomething()函数调用eval()不会创建变量x,因此调用alert()会导致抛出错误,因为x没有定义。
可以在eval()中声明变量和函数,但这些变量或函数只能在被求值的特殊作用域中有效,随后就将被销毁。
6. 其他变化 #
严格模式还有其他一些变化,希望能够注意。首先是抛弃了with语句。非严格模式下的with能够改变解析变支付的路径,但在严格模式下,with被简化掉了。因此,在严格模式使用with会导致语法错误。
// with语句
// 非严格模式:允许
// 严格模式:抛出错误
with(location){
alert(href);
}
严格模式下也去掉了Javascript中的八进制字面量。以0开头的八进制字面量经常会导致很多错误。在严格模式下,八进制字面量已经成为了无效的语法了。
// 使用八进制字面量
// 非严格模式:值为8
// 严格模式:抛出语法错误
var value = 010;
ES5也修改了严格模式下parseInt()的行为。如今,八进制字面量在严格模式下会被当做以0开头的十进制字面量。例如:
// 使用parseInt()解析八进制字面量
// 非严格模式:值为0
// 严格模式:值为10
var value = parseInt("010");