(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
xhas already been declared
The same is true when y is declared with var:
var y = 4;
let y = 7;
TypeError: Identifier
yhas 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.