严格模式


普通模式和严格模式

JS 的编译分为两种模式,普通模式和严格模式。目前为止,我们学习的语法都是在普通模式中。

普通模式的语法十分松懈,比如变量可以隐式声明,函数执行时,显示绑定 this 指向 window 等。这些功能都会给 JS 运行时带来一定的负担,还有可能给开发者带来一些困惑。在 JS 迭代到一个叫 ES5 的版本时,提供了一种新的编译方式,严格模式,它用来禁止这些可能会带来负担或者造成程序不严谨的语法,同时,严格模式

当使用严格模式编译时,程序运行的速度会得到显著的提高,同时也带来一些限制。

开启严格模式

开启严格模式的方式有两种,局部开启和全局开启。如果想要全局开启,可以在程序的开头添加以下字符串:

"use strict";

开启严格模式后,会给程序带来一些限制,比如无法再使用隐式声明了:

"use strict";
foo = 1;

上面这行代码会抛出一个错误,foo 未定义。

严格模式也可以在局部开启,在每个函数的第一行添加上述字符串即可:

foo = 1; // 全局没有开启严格模式,隐式声明不会报错

function bar() {
  "use strict"; // 在函数内开启严格模式
  baz = 1; // 函数执行时,隐式声明报错
}
bar();

严格模式的规则

严格模式中定义了一些规则用于修正普通模式下可能隐式存在的问题。针对目前本系列学习的知识,有以下限制:

禁用隐式声明

如果不给声明变量直接使用,程序不会再隐式声明,而是发出错误。比如:

"use strict";
foo = 1;

语句块中的函数声明将产生块作用域

如果在严格模式中,语句块内的函数声明会产生块作用域,并不会把声明扩展到外层,比如:

"use strict";
{
  function foo() {
    console.log("foo");
  }
}
foo(); // error

上面的代码会抛出一个错误,我们使用一个花括号生成一个语句块,然后把函数声明放到语句块中,此时,函数声明只在语句块中有用。

这种情况容易出现在逻辑分支中,比如:

"use strict";

var a = 10;

if (a > 0) {
  function foo() {
    console.log("foo");
  }
}

foo(); // error

禁用重复属性重复参数

在普通模式中,下列代码不会出错:

function foo(a, a) {
  console.log(a);
}

var bar = {
  a: 1,
  a: "1",
};

普通模式下,重复参数只有最后的参数有效,console.log(a) 只会打印第二个参数 a。对象字面量的重复属性也不会报错,它会覆盖之前的值。

但是在严格模式下,上述声明会产生语法错误(重复属性出错在 Chrome 中无法验证,可以在 IE 中验证)。

备注:重复属性争议较大,虽然严格模式标准中,对象字面量重复设置属性被禁止,但是各个浏览器并没有完全支持。

this 显式绑定改外 undefined

严格模式下,如果在全局中访问 this 关键字,依旧指向全局对象,在浏览器中,JS 的全局对象是 window,所以严格模式中,下列条件依旧成立:

"use strict";
this === window; // true

但是 this 的显式绑定会被指向 undefined

function foo() {
  console.log(this);
}

foo(); // undefined

备注:在普通模式下,this 的显式绑定指向 window

eval 产生内部作用域

严格模式下,eval 函数内部会产生内部作用域,从而无法把变量定义到外部,比如:

"use strict";
eval("var foo = 1;");
console.log(foo); // error  foo is not defined

尽管如此,在严格模式依旧不提倡使用 eval 关键字。

禁用八进制

"use strict";
var a = 017;

八进制语法在严格模式中被禁用。

其他

严格模式还有一些其他限制,它们可能很难遇到,在此不做介绍,如果你想完全了解,可以查看 这里