Search code examples
javascriptsyntax-errortypeerrorreferenceerror

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


While reading a PluralSight Tutorial, it was claimed that a syntax error would prevent previous lines from being executed. 2(); and 2 = 3; were both given as examples.

But upon testing this behavior in Chrome's Console, only 2 = 3; prevented previous lines from executing.

Here's the output for 2(); (I'm using 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

And here is for 2 = 3;

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

As you can see, the first line is executed for 2(); and foo 1 is printed out. But for 2 = 3;, nothing is printed.

So why is one type of error preventing printing and execution of prior code, but the other doesn't, and is this browser-dependent?


Solution

  • This is due to the nature of the ReferenceError. Per an answer of mine:

    If you want to understand the syntax and semantics better, and why this throws a ReferenceError, you can delve into the ECMAScript® 2015 Language Specification. Per the 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.

    Where IsValidSimpleAssignmentTarget is:

    Section 12.14.3 - Assignment Operators - Static Semantics: IsValidSimpleAssignmentTarget

    AssignmentExpression :
      YieldExpression
      ArrowFunction
      LeftHandSideExpression = AssignmentExpression
      LeftHandSideExpression AssignmentOperator AssignmentExpression
    

    1. Return false.

    As you can see, an "early error" is raised if the assignment complies with the definition of AssignmentExpression : LeftHandSideExpression = AssignmentExpression but LeftHandSideExpression is invalid. Since 2 is not an ObjectLiteral, ArrayLiteral, and IsValidSimpleAssignmentTarget returns false, the assignment fails and the ReferenceError is thrown.

    Now, to define the term "early error". Per the specification:

    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.

    That means none of the code is executed when an early error is raised. Because in your assignment, an early ReferenceError is raised, none of the code is executed, and thus, the console is never logged to.

    In the second example, a function call is performed. Step 5 of evaluation throws a TypeError because the result of IsCallable(func) is false (as func is a Number), and the TypeError is thrown. Note that the TypeError is not an early error. Thus, execution of code does happen, and the console is logged to. When the line 2(); is encountered, it is evaluated and the TypeError is thrown.

    This is not browser-dependent because all browsers and JavaScript engines must follow the specification. It should be noted that this was taken from the ECMAScript® 2015 (AKA ES6) Specification, which has not been fully implemented on all engines. I recommend taking a look in the ECMAScript® 2011 (ES5) Specification, in which all modern engines implement fully, though definitions of the above have not changed between both version.


    It should be noted that these are not syntax errors. 2(); is a TypeError because the Number type is not callable. 2 = 3 is a ReferenceError because 2 is an invalid left hand side to be assigned to. Assigning a function to a name that is a numeral is, however, a syntax error. It violates the syntax of a function declaration to do function 2() {}, as the declaration expects an identifier as a name.

    A numeral is a constant, you cannot assign a constant to anything because it is constant. 2 = 3 makes no sense in the real world, and is thus prevented in the specification. Similarly, you cannot do var 2 = function() {}.