(Note: All examples using let
are also valid for const
)
var
is available in all versions of JavaScript, while let
and const
are part of ECMAScript 6 and only available in some newer browsers.
var
is scoped to the containing function or the global space, depending when it is declared:
var x = 4; // global scope
function DoThings() {
var x = 7; // function scope
console.log(x);
}
console.log(x); // >> 4
DoThings(); // >> 7
console.log(x); // >> 4
That means it "escapes" if
statements and all similar block constructs:
var x = 4;
if (true) {
var x = 7;
}
console.log(x); // >> 7
for (var i = 0; i < 4; i++) {
var j = 10;
}
console.log(i); // >> 4
console.log(j); // >> 10
By comparison, let
is block scoped:
let x = 4;
if (true) {
let x = 7;
console.log(x); // >> 7
}
console.log(x); // >> 4
for (let i = 0; i < 4; i++) {
let j = 10;
}
console.log(i); // >> "ReferenceError: i is not defined"
console.log(j); // >> "ReferenceError: j is not defined"
Note that i
and j
are only declared in the for
loop and are therefore undeclared outside of it.
There are several other crucial differences:
In the top scope (outside any functions and blocks), var
declarations put an element in the global object. let
does not:
var x = 4;
let y = 7;
console.log(this.x); // >> 4
console.log(this.y); // >> undefined
Declaring a variable twice using var
doesn't produce an error (even though it's equivalent to declaring it once):
var x = 4;
var x = 7;
With let
, this produces an error:
let x = 4;
let x = 7;
TypeError: Identifier
x
has already been declared
The same is true when y
is declared with var
:
var y = 4;
let y = 7;
TypeError: Identifier
y
has already been declared
However variables declared with let can be reused (not re-declared) in a nested block
let i = 5;
{
let i = 6;
console.log(i); // >> 6
}
console.log(i); // >> 5
Within the block the outer i
can be accessed, but if the within block has a let
declaration for i
, the outer i
can not be accessed and will throw a ReferenceError
if used before the second is declared.
let i = 5;
{
i = 6; // outer i is unavailable within the Temporal Dead Zone
let i;
}
ReferenceError: i is not defined
Variables declared both with var
and let
are hoisted. The difference is that a variable declared with var
can be referenced before its own assignment, since it gets automatically assigned (with undefined
as its value), but let
cannot–it specifically requires the variable to be declared before being invoked:
console.log(x); // >> undefined
console.log(y); // >> "ReferenceError: `y` is not defined"
//OR >> "ReferenceError: can't access lexical declaration `y` before initialization"
var x = 4;
let y = 7;
The area between the start of a block and a let
or const
declaration is known as the Temporal Dead Zone, and any references to the variable in this area will cause a ReferenceError
. This happens even if the variable is assigned before being declared:
y=7; // >> "ReferenceError: `y` is not defined"
let y;
In non-strict-mode, assigning a value to a variable without any declaration, automatically declares the variable in the global scope. In this case, instead of y
being automatically declared in the global scope, let
reserves the variable's name (y
) and does not allow any access or assignment to it before the line where it is declared/initialized.