错误
JavaScript不仅拥有不同的错误 子类型(TypeError
,ReferenceError
,SyntaxError
等等),而且和其他在运行时期间发生的错误相比,它的文法还定义了在编译时被强制执行的特定错误。
尤其是,早就有许多明确的情况应当被作为“早期错误”(编译期间)被捕获和报告。任何直接的语法错误都是一个早期错误(例如,a = ,
),而且文法还定义了一些语法上合法但是无论怎样都不允许的东西。
因为你的代码还没有开始执行,这些错误不能使用try..catch
捕获;它们只是会在你的程序进行解析/编译时导致失败。
提示: 在语言规范中没有要求浏览器(和开发者工具)到底应当怎样报告错误。所以在下面的错误例子中,对于哪一种错误的子类型会被报告或它包含什么样的错误消息,你可能会在各种浏览器中看到不同的形式,
一个简单的例子是正则表达式字面量中的语法。这里的JS语法没有错误,而是不合法的正则表达式将会抛出一个早期错误:
var a = /+foo/; // 错误!
一个赋值的目标必须是一个标识符(或者一个产生一个或多个标识符的ES6解构表达式),所以一个像42
这样的值在这个位置上是不合法的,因此可以立即被报告:
var a;
42 = a; // 错误!
ES5的strict
模式定义了更多的早期错误。例如,在strict
模式中,函数参数的名称不能重复:
function foo(a,b,a) { } // 还好
function bar(a,b,a) { "use strict"; } // 错误!
另一种strict
模式的早期错误是,一个对象字面量拥有一个以上的同名属性:
(function(){
"use strict";
var a = {
b: 42,
b: 43
}; // 错误!
})();
注意: 从语义上讲,这样的错误技术上不是 语法 错误,而是 文法 错误 —— 上面的代码段是语法上合法的。但是因为没有GrammarError
类型,一些浏览器使用SyntaxError
代替。
过早使用变量
ES6定义了一个(坦白地说,让人困惑地命名的)新的概念,称为TDZ(“Temporal Dead Zone” —— 时间死区)
TDZ指的是代码中还不能使用变量引用的地方,因为它还没有到完成它所必须的初始化。
对此最明白的例子就是ES6的let
块儿作用域:
{
a = 2; // ReferenceError!
let a;
}
赋值a = 2
在变量a
(它确实是在{ .. }
块儿作用域中)被声明let a
初始化之前就访问它,所以a
位于TDZ中并抛出一个错误。
有趣的是,虽然typeof
有一个例外,它对于未声明的变量是安全的(见第一章),但是对于TDZ引用却没有这样的安全例外:
{
typeof a; // undefined
typeof b; // ReferenceError! (TDZ)
let b;
}