Search code examples
javascriptreferenceerror

Why does this un-assigned let variable not cause a Reference Error?


Why, in this snippet, does trying to access bar not cause a Reference Error? I've read questions / answers that try to explain the difference between let and var, but none appear to explain the difference in behavior of the top and bottom examples.

var foo;
let bar;

if( foo ) ()=>{}; // I expected this to be fine
if( bar ) ()=>{}; // I expected this to throw a reference error

console.log('finished');

(Feel free to just answer that question, my life story and why I ask below)

I've been trying to break the bad habit of over-using var. While writing some new code, I came across an issue I hadn't seen before: Using if( myValue ) { ... } was throwing a Reference Error for myValue not being defined. "Well, duh, I'm trying to see if it is defined!"

I would declare myValue, and throughout the course of a function, I may assign it a value. Towards the end of the function, I check to see if it had a value, and if so, would perform some extra actions.

I remembered in my reading about let vs var that var will basically act as though you created the container for your value at the top of the scope, whereas let, I thought it would do so at the time you declare it, but seems to do so at the time you assign it. So, I could use var myValue;, let myValue = undefined, or if( typeof myValue !== 'undefined' ) { .. }. I get that the last one is the best bet to ensure this type of thing doesn't happen again, even if it is butt ugly.

Afterwards, I wrote the above little snippet to explain the bug to a co workers... and it worked?!? I'm trying to figure out what exactly was going on here that I may have missed, because I want to understand exactly what went wrong and learn from it. But I'm really scratching my head now, if I wasn't earlier, because I thought I not only figured out the problem, but fixed it... only to discover it may have been something else only tangentially related.

As a side note: My code did declare multiple variables with one let, using commas between them. Could this have been a factor? I did re-read those declarations several times and they are all formatted properly:

let value1 = 3,
    value2,
    value3 = 982,
    // ...
    myValue; // Add ` = undefined` to stop the Reference Error

// ...

if( myValue ) { /* ... */ } // Reference Error thrown here

Solution

  • let bindings are created at the top of the (block) scope containing the declaration, commonly referred to as "hoisting". Unlike variables declared with var, which will start with the value undefined, let variables are not initialized until their definition is evaluated. Accessing the variable before the initialization results in a ReferenceError. The variable is in a "temporal dead zone" from the start of the block until the initialization is processed.

    More info: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let