错误

JavaScript不仅拥有不同的错误 子类型TypeErrorReferenceErrorSyntaxError等等),而且和其他在运行时期间发生的错误相比,它的文法还定义了在编译时被强制执行的特定错误。

尤其是,早就有许多明确的情况应当被作为“早期错误”(编译期间)被捕获和报告。任何直接的语法错误都是一个早期错误(例如,a = ,),而且文法还定义了一些语法上合法但是无论怎样都不允许的东西。

因为你的代码还没有开始执行,这些错误不能使用try..catch捕获;它们只是会在你的程序进行解析/编译时导致失败。

提示: 在语言规范中没有要求浏览器(和开发者工具)到底应当怎样报告错误。所以在下面的错误例子中,对于哪一种错误的子类型会被报告或它包含什么样的错误消息,你可能会在各种浏览器中看到不同的形式,

一个简单的例子是正则表达式字面量中的语法。这里的JS语法没有错误,而是不合法的正则表达式将会抛出一个早期错误:

  1. var a = /+foo/; // 错误!

一个赋值的目标必须是一个标识符(或者一个产生一个或多个标识符的ES6解构表达式),所以一个像42这样的值在这个位置上是不合法的,因此可以立即被报告:

  1. var a;
  2. 42 = a; // 错误!

ES5的strict模式定义了更多的早期错误。例如,在strict模式中,函数参数的名称不能重复:

  1. function foo(a,b,a) { } // 还好
  2. function bar(a,b,a) { "use strict"; } // 错误!

另一种strict模式的早期错误是,一个对象字面量拥有一个以上的同名属性:

  1. (function(){
  2. "use strict";
  3. var a = {
  4. b: 42,
  5. b: 43
  6. }; // 错误!
  7. })();

注意: 从语义上讲,这样的错误技术上不是 语法 错误,而是 文法 错误 —— 上面的代码段是语法上合法的。但是因为没有GrammarError类型,一些浏览器使用SyntaxError代替。

过早使用变量

ES6定义了一个(坦白地说,让人困惑地命名的)新的概念,称为TDZ(“Temporal Dead Zone” —— 时间死区)

TDZ指的是代码中还不能使用变量引用的地方,因为它还没有到完成它所必须的初始化。

对此最明白的例子就是ES6的let块儿作用域:

  1. {
  2. a = 2; // ReferenceError!
  3. let a;
  4. }

赋值a = 2在变量a(它确实是在{ .. }块儿作用域中)被声明let a初始化之前就访问它,所以a位于TDZ中并抛出一个错误。

有趣的是,虽然typeof有一个例外,它对于未声明的变量是安全的(见第一章),但是对于TDZ引用却没有这样的安全例外:

  1. {
  2. typeof a; // undefined
  3. typeof b; // ReferenceError! (TDZ)
  4. let b;
  5. }