0

I've seen code where a ternary operator is used to check whether or not a variable has been declared, and declare it if it has not been. For example:

var num = (typeof num === 'undefined' ? 1 : num);
console.log(num); //1

However, this does not work when using 'let' instead of 'var':

let num = (typeof num === 'undefined' ? 1 : num); //Uncaught ReferenceError: num is not defined

I know that compared to 'var', 'let' has block scoping and prevents redeclaration. I'm unsure how this would cause the ReferenceError in the case above. Could anyone shed some light as to what's going on here? Thanks!

pl61
  • 53
  • 5

3 Answers3

3

You've run into something called hoisting.

Hoisting affects var declaration, but not let or const.

In short words, hoisting moves every var declaration to the top of the code. Meaning for this code:

x = 1;
var y = x + x;
var x;

It is translated to:

var y;      // y is declared, but undefined (thus y === undefined)
var x;      // x is declared, but undefined (thus x === undefined)
x = 1;      // x is defined
y = x + x   // y is defined

Which is why you don't get an error, because x is declared, then defined.

But that is not the case for let and const:

x = 1;
let y = x + x;
let x;

will throw an error, because you used x before it is declared.

EDIT

Read Felix's comment below for details.

yqlim
  • 5,648
  • 3
  • 15
  • 36
  • 2
    Almost. The same algorithm that finds all `var` declarations before the code is executed also finds all `let` and `const` declarations. The difference is that `var` declarations are *initialized* with `undefined`, whereas `let` and `const` are not initialized. Trying to access an uninitialized bindings causes an error. I'd actually avoid the terms "declared" and "defined" because they are not clearly defined (no pun intended). A *binding* (the general term for the result of `var`/`let`/`const` declarations) either exists or does not exist and it is either initialized or not. – Felix Kling Dec 31 '18 at 06:51
0

Not the best way to check variable existence. You should not do it by accessing variable.

If you have to do it do it using:

var barIsDeclared = true; 
try{ bar; }
catch(e) {
    if(e.name == "ReferenceError") {
        barIsDeclared = false;
    }
}

You get reference error in case of constand let variables. It may appear that they are not hoisted in the first iteration phase but that is not true.

Anyway, this is how I test variable existence and it works with no issues.

YetAnotherBot
  • 1,584
  • 2
  • 16
  • 26
0

You're just trying to access to it before initializing it.

let num;
num = (typeof num === 'undefined' ? 1 : num);
console.log(num); //1

this is the actual answer you want.