With ES6, two very important ways to declare a variable were introduced, let
and const
. These were introduced to replace var
which was previous standard way of declaring a variable.
Although by definition let
and var
are functionally similar. They are interpreted differently in some ways.
Temporal Dead Zone
The area of code before the variable is initialized by let
or const
is called Temporal Dead Zone (TDZ)
// Temporal Dead Zone
// Temporal Dead Zone
let a = 1;
console.log(a);
This concept is introduced with let
and const
and is not applicable for var
If we try to access a variable declared using let
or const
before it is initialized returns a Reference Error. This is because of TDZ.
console.log(a); // returns "Reference Error" (a is in TDZ)
let a = 1;
Where as for var
, the console returns undefined
console.log(a); // returns "undefined"
var a = 1;
Scope
There are three types of scopes in JavaScript. Global Scope, Function Scope and Block Scope.
Block Scope is relatively new, and is introduced with ES6, let
and const
Global Scope is the scope of the file/program. Once declared in Global Scope, the variable can be accessed anywhere in the file/program. (Ofcourse, exception is TDZ in the case of let
and const
)
let num = 1;
{
let n = 2;
num = n + num;
console.log(num); // logs 3
}
console.log(num); // logs 3
But if num
is in TDZ...
let num = 1;
{
let n = 2;
let num = n + num; // throws "Reference Error", because num is not initialized in this Block Scope
console.log(num);
}
console.log(num);
Block Scope is the code between { }
Let's try the above code with var
var num = 1;
{
var n = 2;
var num = n + num;
console.log(num); // logs 3
}
console.log(num); // logs 3
Function Scope is the scope inside a function.
let num = 1;
function addNum(n) {
num = n + num;
return num;
}
console.log(addNum(2)); // logs 3
console.log(num); // logs 3
The above code works because num
is the declared in the Block of file/program.
let num = 1;
function addNum(n) {
let num = n + num; // throws "Reference Error", because num is not yet initialized in the block of function
return num;
}
console.log(addNum(2));
console.log(num);
Let's try the same examples with var
var num = 1;
function addNum(n) {
num = n + num;
return num;
}
console.log(addNum(2)); // logs 3
console.log(num); // logs 3
var num = 1;
function addNum(n) {
var num = n + num;
return num;
}
console.log(addNum(2)); // logs NaN
console.log(num); // logs 1
The num
inside the function is being refernced before it's declaration, but since var
doesn't have TDZ, it is initialized as undefined
when it is hoisted. So when the function is called undefined
is added to 2
and returns NaN
If you notice, When num
is declared with var
inside a function, the num
outside the function is not used. But when num
is declared with var
inside a block, the num
outside the block is used. This is because var
is Functional Scoped, not Block Scoped.
Whereas when num
declared with let
, it throwed "Reference Error" when num
is accessed before initialized, because of TDZ and because let
is Block Scoped
Hoisting
All the variables and functions in a JavaScript program are hoisted, i.e., a memory location is allocated to the variables and functions according to thier scopes.
Although let
and const
are hoiseted, a value is not assigned until a value is assigned to the variable creating TDZ in between.