0

I’m sure it’s a little caveat somewhere but, here is the issue:

var x = x || {}; // Works!
let y = y || {}; // ReferenceError: can't access lexical declaration 'y' before initialization
const z = z || {}; // ReferenceError: can't access lexical declaration 'z' before initialization

The let and const cases throw “ReferenceError: can't access lexical declaration 'variableName' before initialization”.

What is going on here? I can kind of understand the const one, but how is let not working either?

Sebastian Simon
  • 14,320
  • 6
  • 42
  • 61
TJBlackman
  • 1,216
  • 1
  • 12
  • 31

1 Answers1

1
  1. Variables declared with var are hoisted to the top of the enclosing function or global scope. They are assigned the initial value of undefined. Hence the example line of code var x = x || {}; is transformed by hoisting and default value initialization into this equivalent code:

    var x = undefined;
    x = x || {};
    

    Because x already has a value when the right-hand side of the assignment statement is evaluated, the code proceeds normally.

    Side note: You can declare a variable with var even after the first assignment (due to top-hoisting), and declaring more than once is idempotent (e.g. var x; var x;).

  2. Variables declared with let and const are hoisted to the top of the enclosing block, but are not given a default value. If such a variable is read before a value is assigned, a ReferenceError is thrown. Your example line of code is transformed by hoisting into this equivalent code:

    let y;
    y = y || {};
    

    To execute the assignment statement, the right side is first evaluated, then its value is assigned to the variable on the left side. But in this case, the right side reads y, which has not been assigned a value yet — hence an error is thrown.

    Everything that is in the same scope as the let statement, but executed earlier (i.e. above let or the right-hand side of a let assignment) is within the Temporal Dead Zone (TDZ).


Note that in JavaScript, a piece of code like let x = x + 1; throws an exception only if execution reaches that statement. Whereas in other languages like Java, the same piece of code is always a compile-time error, even if it’s buried inside an if(false){...}. This emphasizes the behavior of variable hosting, and the fact that JavaScript examines what the code means when it is executed, hence these examples are not syntax errors in a strict sense.

Sebastian Simon
  • 14,320
  • 6
  • 42
  • 61
Nayuki
  • 16,655
  • 5
  • 47
  • 75
  • 4
    [`let` and `const` are hoisted as well](http://stackoverflow.com/q/31219420/1048572), the only difference is that they are not initialised with the default value `undefined`. – Bergi Mar 23 '17 at 04:24
  • @Bergi Thank you so much. Fixing now... – Nayuki Mar 23 '17 at 04:25