JavaScript 中的 严格模式

2,831 阅读4分钟

严格模式:使用严格模式的好处是可以提早知道代码中存在的错误,及时捕获一些可能导致编程错误的 ECMAScript 行为。

严格模式的选择使用

严格模式的编译指示(pragma): "use strict";,支持严格模式的引擎会启动这种模式,而不支持该模式的引擎就当遇到了一个未赋值的字符串字面量,会忽略这个编译指示。

  • 在全局作用域中(函数外部)给出这个编译指示,则整个脚本都将使用严格模式。
  • 在函数作用域中给出这个编译指示,则这个函数将使用严格模式
function test () {
    "use strict";
    ...
}

严格模式的规范

变量

  1. 不允许意外创建全局变量,给一个没有声明的变量赋值,那代码在执行时就会抛出 ReferenceError
// 未声明变量 
// 非严格模式:创建全局变量 
// 严格模式:抛出 ReferenceError
message = "Hello world! ";
  1. 不能对变量调用 delete 操作符
//删除变量 
//非严格模式:静默失败 
//严格模式:抛出 ReferenceError
var color = "red";
delete color;
  1. 严格模式下对变量名也有限制,不能使用 implements、interface、let、package、 private、protected、public、static 和 yield 标识符作为变量名,使用以上标识符作为变量名会导致语法错误。

对象

  1. 为只读属性赋值会抛出 TypeError
  2. 对不可配置的(nonconfigurable)的属性使用 delete 操作符会抛出 TypeError
  3. 为不可扩展的(nonextensible)的对象添加属性会抛出 TypeError
  4. 使用对象字面量时,属性名必须唯一
// 重名属性 
// 非严格模式:没有错误,以第二个属性为准 
// 严格模式:抛出语法错误
var person = {
    name: "Nicholas",
    name: "Greg"
};

函数

  1. 严格模式要求命名函数的参数必须唯一
//重名参数 
//非严格模式:没有错误,只能访问第二个参数 
//严格模式:抛出语法错误
function sum (num, num){
    // todo
}
  1. 在非严格模式下,修改命名参数的值也会反映到arguments对象中,而严格模式下这两个值是完全独立的
//修改命名参数的值 
//非严格模式:修改会反映到 arguments 中 
//严格模式:修改不会反映到 arguments 中
function showValue(value) {
    value = "Foo";
    console.log(value); //"Foo" 
    console.log(arguments[0]); //非严格模式:"Foo",严格模式:"Hi"
}
showValue("Hi");
  1. arguments.callee 和 arguments.caller,在非严格模式下,这两个属性一个引用函数本身,一个引用调用函数。而在严格模式下,访问哪个属性都会抛出 TypeError
//访问 arguments.callee 
//非严格模式:没有问题 
//严格模式:抛出 TypeError
function factorial(num){
    if (num <= 1) {
        return 1;
    } else {
        return num * arguments.callee(num-1)
    }
}
var result=factorial(5);
  1. 严格模式对函数名也做出了限制,不允许用implements、interface、let、package、private、protected、public、static 和 yield 作为函数名
  2. 只能在脚本的顶级和在函数内部声明函数
//在 if 语句中声明函数 
//非严格模式:将函数提升到 if 语句外部 
//严格模式:抛出语法错误
if (true){
    function doSomething(){
        // todo 
    }
}

eval()

  1. 在严格模式中,它在包含上下文中不再创建变量或函数
//使用 eval()创建变量
//非严格模式:弹出对话框显示 10
//严格模式:调用 alert(x)时会抛出 ReferenceError
function doSomething(){
    eval("var x=10");
    alert(x);
}
  1. 可以在 eval()中声明变量和函数,但这些变量或函数只能在被求值的特殊作用域中有效,随后就将被销毁
"use strict";
var result = eval("var x=10, y=11; x+y");
alert(result);  // 21

eval 和 arguments

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

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

抑制this

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

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

其他变化

  1. 非严格模式下的 with 语句能够改变解析标识符的路径。严格模式下,with 被简化掉了
//with 的语句用法
//非严格模式:允许
//严格模式:抛出语法错误
with(location){
    alert(href);
}
  1. 严格模式去掉了 JavaScript 中的八进制字面量
//使用八进制字面量 
//非严格模式:值为 8 
//严格模式:抛出语法错误
var value = 010;
  1. 严格模式下 parseInt()的行为,八进制字面量在严格模式下会被当作以 0 开头的十进制字面量
//使用 parseInt()解析八进制字面量 
//非严格模式:值为 8 
//严格模式:值为 10
var value = parseInt("010");