Here are few differences between using let
and var
:
1. Redeclaration:
In strict mode, var
will let you re-declare the same variable in the same scope while let
throws a SyntaxError
.
'use strict';
var foo = "foo1";
var foo = "foo2"; // No problem, 'foo' is replaced.
let bar = "bar1";
let bar = "bar2"; // SyntaxError: Identifier 'bar' has already been declared
2. Creating global object property:
let
, in contrast to var
, doesn't make a property on the global object:
var foo = "Foo"; // globally scoped
let bar = "Bar"; // globally scoped
console.log(window.foo); // Foo
console.log(window.bar); // undefined
3. Scoping rules:
The most important difference is the scoping rules. Variables declared by var
keyword are scoped to the immediate function body while let
variables are scoped to the immediate enclosing block meant by { }
.
function run() {
var foo = "Foo";
let bar = "Bar";
console.log(foo, bar); // Foo Bar
{
let baz = "Bazz";
console.log(baz); // Bazz
}
console.log(baz); // ReferenceError
}
run();
The motivation behind why let keyword was introduced with the language was function scope is confusing and was one of the main sources of bugs in JavaScript.
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("Value: " + i);
};
}
for (var j = 0; j < 3; j++) {
// and now let's run each one to see
funcs[j]();
}
Value: 3
was output to console each time funcs[j]();
was used since anonymous functions were bound to the same variable.
Developers needed to make immediately invoked functions to catch correct value from the loops yet that was also hairy.
4. Hoisting:
While variables declared with var
keyword are hoisted (initialized with undefined before the code is run) which implies they are accessible in their enclosing scope even before they are declared:
function run() {
console.log(foo); // undefined
var foo = "Foo";
console.log(foo); // Foo
}
run();
let
variables are not initialized until their definition is evaluated. Accessing them before the initialization brings about a ReferenceError
. Variable said to be in "temporal dead zone" from the beginning of the block until the initialization is handled.
function checkHoisting() {
console.log(foo); // ReferenceError
let foo = "Foo";
console.log(foo); // Foo
}
checkHoisting();