Wenzi

Javascript的严格模式

蚊子前端博客
发布于 2015/02/14 07:00
ES5最早引入了“严格模式”(strict mode)的概念。严格模式不是束缚了开发者的手脚,而是更加规范了Javascript的开发,方便代码的多浏览器兼容和以后的维护

在严格模式下,能够在函数内部选择进行较为严格的全局或局部的错误条件检测。使用严格模式的好处是可以提早知道代码中存在的错误,即使捕获一些可能导致编程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, staticyield作为变量名。这些都是保留字,将来的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, staticyield作为函数名。
对函数的最后一点限制,就是只能在脚本的顶级和在函数内部声明函数。而在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");
阅读(669)
Simple Empty
No data