Variables declared with var
are hoisted, i.e. variable declared with var
can be used before it is declared.
age = 20;
var age;
console.log(age); // 20
In the above code example, we were able to use the variable age
before it was declared. This works because of the concept known as hoisting.
This happens because, before starting the step-by-step execution of the code, javascript engine scans through the code, looking for var
declarations and hoisting (lifting) them to the top of the scope.
It's important to note that only declarations are hoisted, not their initializers. When var
declarations are hoisted, javascript engine assigns the value undefined
to that variable.
console.log(age); // undefined
var age = 20;
In the above code example, variable age
was hoisted at the top of the scope but its value is undefined
. Variable age
will only be assigned the value 20
when the second line of code is executed during the step-by-step execution of the code.
let
and const
Declarations are also Hoisted
Unlike variables declared with var
, variables declared with let
or constants declared with const
can't be used before they are declared.
console.log(age); // error: Cannot access uninitialized variable
let age = 20;
In the above code example, we cannot access age
variable before it is declared. Instead, we get an error telling us that we cannot access the variable age
before it is initialized.
Apparently, the let
and const
declarations are not hoisted like var
declarations. But that is a misconception. let
and const
declarations are hoisted, too. They are just hoisted differently.
Consider the following code example:
let age;
function foo() {
age = 20; // error: Cannot access uninitialized variable
let age = 30;
}
foo();
If the let
declarations weren't hoisted, first line of code inside the foo
function should have assigned the value to the variable age
that is defined outside the function foo
. But that is not the case. Instead, we get an error.
This behaviour avoids confusing code. Imagine, in the above code example, the identifier age
inside the foo
function referring to two different variables defined in two different scopes. Hoisting of let
and const
declarations prevents such confusing code.
But if let
and const
declarations are hoisted, then why can we not access the variables declared with let
and constants declared with const
, before they are declared?
Answer to the above question is Temporal Dead Zone (TDZ).
Temporal Dead Zone is the period of time during which the let
and const
declarations cannot be used to refer to anything at all.
As with var
declarations, javascript engines processes the let
and const
declarations before starting the step-by-step execution of the code. Difference is that, instead of assigning the value undefined
, javascript engine marks the identifier declared using let
or const
as "not yet initialized".
Temporal Dead Zone (TDZ) starts when the code execution enters the block which contains the let
or const
declaration and continues until the declaration is run.
Comments in the following code example show the start and end of Temporal Dead Zone:
let age;
function foo() {
// temporal dead zone start
age = 20;
let age = 30;
// temporal dead zone end
}
foo();
Temporal Dead Zone starts as soon as the code execution enters the foo
function body and continues until the declaration of variable age
is executed.
Temporal Dead Zone is Temporal, not Spatial
One important thing to understand about TDZ is that it is temporal (related to time) and not spatial (related to space or location).
Following code example will make it much more clear:
function foo() {
function bar() {
console.log(age); // 20
}
let age = 20;
bar();
}
foo();
As you can see in the above code example, variable age
is used in a function bar
that is declared before the declaration of the variable age
but we didn't get any error because of Temporal Dead Done. Why is that?
It's because the Temporal Dead Zone relates to the time until the declaration of the variable age
is run and not to the space/location above the declaration where the identifier can't be used.
The above code example works because by the time bar
function is called, declaration of variable age
has already been executed. That's why we didn't get any error and the function bar
logged the value of variable age
.
If the Temporal Dead Zone was spatial, then the above code example would have given an error because of the usage of variable age
in the code that is above the declaration of that variable.
Summary
let
andconst
declarations are hoisted too, its just that they are hoisted differently thanvar
declarations- Temporal Dead Zone (TDZ) relates to the period of time during which the identifier can't be used