JavaScript Scope Difference between var and let

Help us to keep this website almost Ad Free! It takes only 10 seconds of your time:
> Step 1: Go view our video on YouTube: EF Core Bulk Insert
> Step 2: And Like the video. BONUS: You can also share it!

Example

(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:

Global variable declaration

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

Re-declaration

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

Hoisting

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.



Got any JavaScript Question?