4

With let vs. var I've learned that the major difference is that let variables are scoped to the nearest block and are not hoisted. Also let variables can be reassigned but cannot be redeclared within the same scope. Why then does this code return a "not defined" error?

let x = 10;
if (true) {
    console.log(x);
    let x = 11;
}

returns:

Uncaught ReferenceError: x is not defined(…)

While:

let x = 10;
if (true) {
    console.log(x);
}

logs 10 without an error?

docta_faustus
  • 2,383
  • 4
  • 30
  • 47
  • 1
    I'm not sure I understand your confusion. Everything looks normal here. What _exactly_ in your example surprises you? Do you understand what block scope is? – DavidS Mar 15 '16 at 20:15
  • I see it now. Because of the "let x = 11" in the first example, x is hoisted to that conditional block which makes it undefined when it is logged, correct? – docta_faustus Mar 15 '16 at 20:18
  • 1
    Possible duplicate of [What is the temporal dead zone?](http://stackoverflow.com/questions/33198849/what-is-the-temporal-dead-zone) – adeneo Mar 15 '16 at 20:20
  • Read this https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let – Aj1 Mar 15 '16 at 20:25

2 Answers2

1

The main difference between var and let is that:

var is hoisted to the wrapping function block.

let is hoisted to the wrapping {} block

The second code sample doesn't have the same reference conflict as the first because you're declaring x prior to referencing it in the following if block.


EDIT To address Pointy's comment below:

You're experiencing the ReferenceError because of the temporal dead zone

If you reference a variable defined by let within the same block before it is defined you will receive this error.

From MDN let Docs

In ECMAScript 2015, let will hoist the variable to the top of the block. However, referencing the variable in the block before the variable declaration results in a ReferenceError. The variable is in a "temporal dead zone" from the start of the block until the declaration is processed.

function do_something() { console.log(foo); // ReferenceError let foo = 2; }

peteb
  • 18,552
  • 9
  • 50
  • 62
-1

let variables are actually hoisted (within the block). From MDN:

In ECMAScript 2015, let will hoist the variable to the top of the block.

madox2
  • 49,493
  • 17
  • 99
  • 99
  • 2
    They're *kind-of* hoisted, but it's different than what happens with `var` variables. A `var` variable referenced before its declaration will not generate a reference error, but `let` variables explicitly will. From the spec: *The variables are created when their containing Lexical Environment is instantiated but may not be accessed in any way until the variable’s LexicalBinding is evaluated.* – Pointy Mar 15 '16 at 20:12
  • 1
    This answer corrects the user on one point, but it doesn't actually explain the behaviour he sees in the example – DavidS Mar 15 '16 at 20:14
  • Note the part about *"temporal dead zone"* – adeneo Mar 15 '16 at 20:14