Question
ECMAScript 6 introduced [the let
statement](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Statements/let).
I've heard that it's described as a local variable, but I'm still not quite
sure how it behaves differently than the var
keyword.
What are the differences? When should let
be used instead of var
?
Answer
Scoping rules
The main difference is scoping rules. Variables declared by var
keyword are
scoped to the immediate function body (hence the function scope) while let
variables are scoped to the immediate enclosing block denoted by { }
(hence the block scope).
function run() {
var foo = "Foo";
let bar = "Bar";
console.log(foo, bar); // Foo Bar
{
var moo = "Mooo"
let baz = "Bazz";
console.log(moo, baz); // Mooo Bazz
}
console.log(moo); // Mooo
console.log(baz); // ReferenceError
}
run();
The reason why let
keyword was introduced to the language was function scope
is confusing and was one of the main sources of bugs in JavaScript.
Take a look at this example from [another Stack Overflow question](https://stackoverflow.com/questions/750486/javascript-closure- inside-loops-simple-practical-example):
var funcs = [];
// let's create 3 functions
for (var i = 0; i < 3; i++) {
// and store them in funcs
funcs[i] = function() {
// each should log its value.
console.log("My value: " + i);
};
}
for (var j = 0; j < 3; j++) {
// and now let's run each one to see
funcs[j]();
}
My value: 3
was output to console each time funcs[j]();
was invoked since
anonymous functions were bound to the same variable.
People had to create immediately invoked functions to capture correct values from the loops but that was also hairy.
Hoisting
Variables declared with var
keyword are [hoisted and
initialized](https://dev.to/godcrampy/the-secret-of-hoisting-in-javascript-
egi) which means they are accessible in their enclosing scope even before they
are declared, however their value is undefined
before the declaration
statement is reached:
function checkHoisting() {
console.log(foo); // undefined
var foo = "Foo";
console.log(foo); // Foo
}
checkHoisting();
let
variables are [hoisted but not
initialized](https://stackoverflow.com/questions/31219420/are-variables-
declared-with-let-or-const-hoisted) until their definition is evaluated.
Accessing them before the initialization results in a ReferenceError
. The
variable is said to be in [the temporal dead
zone](https://stackoverflow.com/questions/33198849/what-is-the-temporal-dead-
zone) from the start of the block until the declaration statement is
processed.
function checkHoisting() {
console.log(foo); // ReferenceError
let foo = "Foo";
console.log(foo); // Foo
}
checkHoisting();
Creating global object property
At the top level, let
, unlike var
, does not create a property on the
global object:
var foo = "Foo"; // globally scoped
let bar = "Bar"; // globally scoped but not part of the global object
console.log(window.foo); // Foo
console.log(window.bar); // undefined
Redeclaration
In strict mode, var
will let you re-declare the same variable in the same
scope while let
raises a SyntaxError.
'use strict';
var foo = "foo1";
var foo = "foo2"; // No problem, 'foo1' is replaced with 'foo2'.
let bar = "bar1";
let bar = "bar2"; // SyntaxError: Identifier 'bar' has already been declared