Search code examples
javascriptnode.jsv8

const and let variable shadowing in a switch statement


I have the following code. The only interesting part is that I redeclare productId in the second switch case.

let productId = 1;

const check = true;

switch (check) {
  case false:
    console.log(productId);
    break;
  case true:
    let productId = 2;
    console.log(productId);
    break;
}

If I set check to true, then the code works correctly and prints

2

If I set check to false, then the code gives a ReferenceError

/home/osama/workspace/test/javascript.js:7
        console.log(productId);
                    ^

ReferenceError: productId is not defined
    at Object.<anonymous> (/home/osama/workspace/test/javascript.js:7:21)
    at Module._compile (internal/modules/cjs/loader.js:778:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
    at Function.Module._load (internal/modules/cjs/loader.js:585:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)
    at startup (internal/bootstrap/node.js:283:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:622:3)

If I use var to declare productId then the code works correctly regardless of the value of check.

I realize that the let/const statement is shadowing the global variable in someway, but my question is:

Why does the declaration of a variable inside a switch statement, cause the global variable to become undefined and throw a ReferenceError?


Solution

  • Hoisting and Temporal Dead Zone!

    let and const get hoisted to the nearest block, so it becomes something like this:

    switch (check) {
      let productId;
      case false:
        console.log(productId);
        break;
      case true:
        productId = 2;
        console.log(productId);
        break;
    }
    

    and thus because of temporal dead zone, the ReferenceError comes up