JS严格模式

通过严格模式,可以在函数内部 选择进行较为严格的全局或局部的错误条件检测。使用严格模式的好处是可以提早知道代码中存在的错误,及时捕获一些可能导致编程错误的ECMAScript行为。
支持严格模式的浏览器包括IE10+、Firefox 4+、Safari 5.1+和Chrome。

选择使用

要选择进入严格模式,可以使用严格模式的编译指示:

"use strict";

这种语法可以向后兼容那些不支持严格模式的JavaScript引擎。支持严格模式的引擎会启动这种模式,而不支持该模式的引擎就当遇到了一个未赋值的字符串字面量,会忽略这个编译指示。
如果是在全局作用域中(函数外部)给出这个编译指示,则整个脚本都将使用严格模式。也可以只在函数中打开严格模式:

function doSomething(){ 
    "use strict";

    //其他代码
}

变量

在严格模式下,什么时候创建变量以及怎么创建变量都是有限制的。首先,不允许意外创建全局变量。

//未声明变量 
//非严格模式:创建全局变量 
//严格模式:抛出 ReferenceError
message = "Hello world! ";

其次,不能对变量调用delete操作符。非严格模式允许这样操作,但会静默失败(返回false)。 而在严格模式下,删除变量也会导致错误。

//删除变量
//非严格模式:静默失败 
//严格模式:抛出 ReferenceError
var color = "red"; 
delete color;

严格模式下对变量名也有限制。特别地,不能使用implementsinterfaceletpackageprivateprotectedpublicstaticyield作为变量名。这些都是保留字。在严格模式下,用以上标识符作为变量名会导致语法错误。

对象

一般来说,非严格模式下会静默失败的情形,在严格模式下就会抛出错误。
在下列情形下操作对象的属性会导致错误:

  • 为只读属性赋值会抛出TypeError
  • 对不可配置的的属性使用delete操作符会抛出TypeError
  • 为不可扩展的的对象添加属性会抛出TypeError

使用对象的另一个限制与通过对象字面量声明对象有关。在使用对象字面量时,属性名必须唯一。例如:

//重名属性 
//非严格模式:没有错误,以第二个属性为准 
//严格模式:抛出语法错误
var person = { 
    name: "Nicholas", 
    name: "Greg" 
};

函数

首先,严格模式要求命名函数的参数必须唯一。

//重名参数 
//非严格模式:没有错误,只能访问第二个参数 
//严格模式:抛出语法错误
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");

在函数内部,value被改为"Foo"。在非严格模式下,这个修改也会改变arguments[0]的值,但在严格模式下,arguments[0]的值仍然是传入的值。
另一个变化是淘汰了arguments.calleearguments.caller。在非严格模式下,这两个属性一个引用函数本身,一个引用调用函数。而在严格模式下,访问哪个属性都会抛出TypeError

//访问 arguments.callee 
//非严格模式:没有问题 
//严格模式:抛出 TypeError
function factorial(num){
    if (num <= 1) {
        return 1;
    } else {
        return num * arguments.callee(num-1)
    }
}
var result=factorial(5);

类似地,尝试读写函数的caller属性,也会导致抛出TypeError。所以,对于上面的例子而言, 访问factorial.caller也会抛出错误。
与变量类似,严格模式对函数名也做出了限制,不允许用implementsinterfaceletpackageprivateprotectedpublicstaticyield作为函数名。
对函数的最后一点限制,就是只能在脚本的顶级和在函数内部声明函数。也就是说,在if语句中声明函数会导致语法错误:

//在 if 语句中声明函数 
//非严格模式:将函数提升到 if 语句外部 
//严格模式:抛出语法错误
if (true){
    function doSomething(){ 
          //...
    }
}

eval()

eval()函数在严格模式下也得到了提升。最大的变化就是它在包含上下文中不再创建变量或函数。

//使用 eval()创建变量
//非严格模式:弹出对话框显示 10
//严格模式:调用 alert(x)时会抛出 ReferenceError
function 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

在调用alert()时,尽管xy已经不存在了,result变量的值仍然是有效的。

eval与arguments

严格模式已经明确禁止使用evalarguments作为标识符,也不允许读写它们的值。

//把eval和arguments作为变量引用 
//非严格模式:没问题,不出错 
//严格模式:抛出语法错误
var eval = 10;
var arguments = "Hello world!";

在非严格模式下,可以重写eval,也可以给arguments赋值。但在严格模式下,这样做会导致语法错误。不能将它们用作标识符,意味着以下几种使用方式都会抛出语法错误:

  • 使用var声明;
  • 赋予另一个值;
  • 尝试修改包含的值,如使用++;
  • 用作函数名;
  • 用作命名的函数参数;
  • try-catch语句中用作例外名。

抑制this

在非严格模式下使用函数的apply()call()方法时,nullundefined值会被转换为全局对象。而在严格模式下,函数的this值始终是指定的值,无论指定的是什么值。

//访问属性
//非严格模式:访问全局属性 
//严格模式:抛出错误,因为this的值为null
var color = "red";
function displayColor(){ 
    alert(this.color);
}
displayColor.call(null);

其他变化

首先是抛弃了with语句。非严格模式下的with语句能够改变解析标识符的路径,但在严格模式下,with被简化掉了。因此,在严格模式下使用with会导致语法错误。

//with的语句用法 
//非严格模式:允许 
//严格模式:抛出语法错误
with(location){ 
    alert(href);
}

严格模式也去掉了JavaScript中的八进制字面量。以0开头的八进制字面量过去经常会导致很多错误。在严格模式下,八进制字面量已经成为无效的语法了。

//使用八进制字面量 
//非严格模式:值为 8 
//严格模式:抛出语法错误
var value = 010;

八进制字面量在严格模式下会被当作以0开头的十进制字面量。

//使用parseInt()解析八进制字面量 
//非严格模式:值为 8 
//严格模式:值为 10
var value = parseInt("010");

你可能感兴趣的:(JS严格模式)