严格模式

当启用了严格模式(strict mode)后,JavaScript 就会在执行代码时变得更为严格。我们只需在文件或函数体顶部放置字符串"use strict"就可以启用严格模式了。下面是示例代码:

  1. function canYouSpotTheProblem() {
  2. "use strict";
  3. for (counter = 0; counter < 10; counter++) {
  4. console.log("Happy happy");
  5. }
  6. }
  7. canYouSpotTheProblem();
  8. // → ReferenceError: counter is not defined

通常,当你忘记在绑定前面放置let时,就像在示例中的counter一样,JavaScript 静静地创建一个全局绑定并使用它。 在严格模式下,它会报告错误。 这非常有帮助。 但是,应该指出的是,当绑定已经作为全局绑定存在时,这是行不通的。 在这种情况下,循环仍然会悄悄地覆盖绑定的值。

严格模式中的另一个变化是,在未被作为方法而调用的函数中,this绑定持有值undefined。 当在严格模式之外进行这样的调用时,this引用全局作用域对象,该对象的属性是全局绑定。 因此,如果你在严格模式下不小心错误地调用方法或构造器,JavaScript 会在尝试从this读取某些内容时产生错误,而不是愉快地写入全局作用域。

例如,考虑下面的代码,该代码不带new关键字调用构造器,以便其this不会引用新构造的对象:

  1. function Person(name) { this.name = name; }
  2. let ferdinand = Person("Ferdinand"); // oops
  3. console.log(name);
  4. // → Ferdinand

虽然我们错误调用了Person,代码也可以执行成功,但会返回一个未定义值,并创建名为name的全局绑定。而在严格模式中,结果就不同了。

  1. "use strict";
  2. function Person(name) { this.name = name; }
  3. let ferdinand = Person("Ferdinand");
  4. // → TypeError: Cannot set property 'name' of undefined

JavaScript 会立即告知我们代码中包含错误。这种特性十分有用。

幸运的是,使用class符号创建的构造器,如果在不使用new来调用,则始终会报错,即使在非严格模式下也不会产生问题。

严格模式做了更多的事情。 它不允许使用同一名称给函数赋多个参数,并且完全删除某些有问题的语言特性(例如with语句,这是错误的,本书不会进一步讨论)。

简而言之,在程序顶部放置"use strict"很少会有问题,并且可能会帮助你发现问题。