为什么这个 ReferenceError 会阻止所有执行而这个 TypeError 不会?

Why does this ReferenceError prevent all execution when this TypeError does not?

在阅读 PluralSight Tutorial 时,有人声称语法错误会阻止前几行的执行。 2();2 = 3; 都作为示例给出。

但是在 Chrome 的控制台中测试此行为后,只有 2 = 3; 阻止了前面几行的执行。

这是 2(); 的输出(我正在使用 Shift+Enter):

console.log("foo 1");
2();
console.log("foo 2");
VM224:1 foo 1
VM224:2 Uncaught TypeError: 2 is not a function
    at <anonymous>:2:2

这里是 2 = 3;

console.log("foo 1");
2 = 3;
console.log("foo 2");
VM202:2 Uncaught ReferenceError: Invalid left-hand side in assignment

可以看到,第一行执行了2();,打印了foo 1。但是对于 2 = 3;,什么都不打印。

那么,为什么一种类型的错误会阻止先前代码的打印和执行,而另一种则不会,这是否取决于浏览器?

这是 ReferenceError 的性质造成的。每 :

如果您想更好地理解语法和语义,以及为什么会抛出 ReferenceError,您可以深入研究 ECMAScript® 2015 Language Specification。根据规范:

Section 12.14.1 - Assignment Operators - Static Semantics: Early Errors

AssignmentExpression : LeftHandSideExpression = AssignmentExpression

It is an early Reference Error if LeftHandSideExpression is neither an ObjectLiteral nor an ArrayLiteral and IsValidSimpleAssignmentTarget of LeftHandSideExpression is false.

其中 IsValidSimpleAssignmentTarget 是:

Section 12.14.3 - Assignment Operators - Static Semantics: IsValidSimpleAssignmentTarget

AssignmentExpression :
  YieldExpression
  ArrowFunction
  LeftHandSideExpression = AssignmentExpression
  LeftHandSideExpression AssignmentOperator AssignmentExpression

1. Return false.

如您所见,如果赋值符合 AssignmentExpression : LeftHandSideExpression = AssignmentExpression[=13 的定义,则会引发 "early error" =] 无效。由于 2 不是 ObjectLiteralArrayLiteralIsValidSimpleAssignmentTarget returns false,赋值失败并抛出 ReferenceError

现在,定义术语"early error"。根据规范:

Section 16 - Errors

[...] An early error is an error that can be detected and reported prior to the evaluation of any construct in the Program containing the error.

这意味着 none 的代码在出现早期错误时执行。因为在您的作业中,引发了早期的 ReferenceError,执行了 none 代码,因此永远不会登录到控制台。

在第二个示例中,function call is performed. Step 5 of evaluation throws a TypeError because the result of IsCallable(func) 为假(因为 funcNumber),并且抛出 TypeError。请注意 TypeError 而不是 早期错误。因此,确实会执行代码,并且会记录到控制台。当遇到行 2(); 时,对其求值并抛出 TypeError

浏览器相关,因为所有浏览器和 JavaScript 引擎都必须遵循规范。应该注意的是,这取自 ECMAScript® 2015 (AKA ES6) 规范,该规范尚未在所有引擎上完全实现。我建议查看 ECMAScript® 2011 (ES5) 规范,其中所有现代引擎都完全实现,尽管上述定义在两个版本之间没有改变。


需要注意的是,这些不是语法错误。 2();TypeError 因为 Number 类型不可调用。 2 = 3ReferenceError 因为 2 是要分配给的无效左侧。但是,将函数分配给数字名称是语法错误。它违反了 function declaration to do function 2() {}, as the declaration expects an identifier 作为名称的语法。

数字是常量,你不能将常量分配给任何东西,因为它是常量。 2 = 3 在现实世界中没有意义,因此在规范中被禁止。同样,你不能做 var 2 = function() {}.