In general, this is how hoisting works:
- the declaration of the variable is moved to the top
- the variable is initialized with a special "hoisted" value
- when the program reaches the
var/let/const
line, the variable is re-initialized with the value mentioned on that line (or undefined
if there's none).
Now, your example can be simplified down to this:
console.log(a)
let a = 150
which is actually:
a = <hoisted value>
console.log(a)
a = 150
It throws an error because, for let
and const
, the hoisted value is a special object that raises an error when you try to access it.
On the other side, the hoisted value for var
is just undefined
, so this will print undefined
without throwing an error:
console.log(a)
var a = 150
Also, there's some confusion (including this very thread) about which variable types are hoisted, and a so-called "dead zone" for let/const
vars. It's simpler to think of things this way: everything is hoisted, that is, all variable bindings in a block are created before entering the block. The only difference between var
and let/const
in this regard is that with the latter you are not allowed to use a binding until you initialize it with a value.
See https://stackoverflow.com/a/31222689/989121 for more details.