Does using let and const really prevent hoisting?
While going through ES6
, I came to know about let
and const
keywords and it was mentioned there that with these keywords we no longer have to worry about hoisting. This made me curious to know how exactly do they do that.
While looking for possible explanations i came across this.
It appears that let declarations (and const
, which works the same way) may not be hoisted, since a variable declared using let does not appear to exist before it is assigned a value. however let and const are hoisted (like var
, class
and function
), but there is a period between entering scope and being declared where they cannot be accessed. This period is the temporal dead zone (TDZ).
What’s TDZ now? ES6
mentions so called TDZ (stands for Temporal Dead Zone) — this is the region of a program, where a variable or a parameter cannot be accessed until it’s initialized (i.e. received a value).
We’ll understand the above statement by going through this example
Here we have two scopes, one is the global scope and the other is the scope of function f.
When control flow encounters this line
console.log(a)
It checks for a’s declaration inside f()
, after failing to find it there it checks for it’s declaration in global scope but a
is declared after invocation of f()
.
It will give ReferenceError instead of ReferenceError: a is not defined which is the error that JavaScript throws when it is unable to locate the declaration of currently accessed variable. It answers one thing that our control flow is aware about the declaration of variable we are currently accessing and that’s what hoisting is.
Only problem that our control flow is facing is that even after being aware about declaration of a
it is not able get a reference of a
. The reason behind this is that variable a
has entered a temporal dead zone right at the start of the global scope and only comes out of it when control flow encounters this line
let a = 1;
If it had not been initialized with any value then it would have been assigned undefined
because that’s the default value a variable is assigned in JavaScript.
Now, if we take a look at another example
After running this example we’ll not get ReferenceError because a
has already been declared and called out of the temporal dead zone before invoking f()
and our control flow is able to get the reference of a
.
Why only Temporal Dead Zones?
- To catch programming errors: Being able to access a variable before its declaration is strange. If you do so, it is normally by accident and you should be warned about it.
- For
const:
Makingconst
work properly is difficult. Quoting Allen Wirfs-Brock: “TDZs ... provide a rational semantics forconst
. There was significant technical discussion of that topic and TDZs emerged as the best solution.”let
also has a temporal dead zone so that switching betweenlet
andconst
doesn’t change behavior in unexpected ways.
I would recommend reading this technical discussion, It will give you a better insight into the things.
I hope my this effort made you more aware about what happens behind the scenes. From now on if somebody says that let and const are good because they avoid hoisting, just give them a tour of the temporal dead zones.