ES6 has introduced a new way to declare variables, the let
keyword. This means we now have two methods of declaring variables, var
and let
. But how does the let
keyword differ from the var
keyword?
Basically this boils down to scope – let
uses block scope and var
uses function scope.
But what’s the difference between block scope and function scope?
Function Scope
Function scope means that the variable is available throughout the function in which it was declared. For example:
(function() {
var x = 1;
{
var x = 2;
console.log(x); // returns 2
}
console.log(x); // returns 2
}());
In the above code, although it looks like we are declaring a new variable with var x = 2;
what we are actually doing is changing the value of the existing x
variable.
This is made clear with the second console.log
statement, which outputs the value 2. This demonstrates that var x = 2;
does not declare a new variable, and that the x
variable within the block statement is indeed a reference to the existing x
variable. If var
was block scoped, the second console.log
statement would have output the value 1.
Contrast this to an example with let
– which is block scoped.
Block Scope
Block scope means that the variable is scoped to the block in which it was declared – which is not necessarily the function in which it was declared:
(function() {
let x = 1;
{
let x = 2;
console.log(x); // returns 2
}
console.log(x); // returns 1
}());
In this example notice how the second console.log
statement correctly outputs the value 1.
This demonstrates that let
is indeed block scoped. The let x = 2;
statement declares a new variable and initialises it with the value 2. This new variable is scoped to the block, which can be verified by the second console.log
statement which returns the value of the first x
variable – the value 1.
What about mixing the two?
What happens when we declare the first occurrence of x
with var
, and the second occurrence with let
? The first x
will be scoped to the function, because var
is function scoped, and the second x
is scoped to the block, because let
is block scoped.
(function() {
var x = 1;
{
let x = 2;
console.log(x); // returns 2
}
console.log(x); // returns 1
}());
As you can see above, this works as expected. This is because the second occurrence of x
is scoped to the block, this creates a new variable within a new scope and it’s this variable that we access within this block – so our changes are not affecting the function scoped x
.
How did this work before let?
Before let
, you would have to use function scope:
(function()
var x = 1;
(function() {
var x = 2;
console.log(x); // returns 2
}());
console.log(x); // returns 1
}());
In this example, we utilise the fact that var
is function scoped and create a new immediate anonymous function.
We then declare the second x
variable within this new scope. This new function scope provides encapsulation and ensures that the second var
statement declares a new variable within a new scope – and does not mutate the existing x
variable.