Overview

  • The scope of a variable defined with var is function scope or declared outside any function, global.
  • The scope of a variable defined with let is block scope.
function varvslet() {
  console.log(i); // i is undefined due to hoisting
  // console.log(j); // ReferenceError: j is not defined

  for( var i = 0; i < 3; i++ ) {
    console.log(i); // 0, 1, 2
  };

  console.log(i); // 3
  // console.log(j); // ReferenceError: j is not defined

  for( let j = 0; j < 3; j++ ) {
    console.log(j);
  };

  console.log(i); // 3
  // console.log(j); // ReferenceError: j is not defined
}

Difference Details

  • Variable Hoisting

    let will not hoist to the entire scope of the block they appear in. By contrast, var could hoist as below.

{
  console.log(c); // undefined. Due to hoisting
  var c = 2;
}

{
  console.log(b); // ReferenceError: b is not defined
  let b = 3;
}
  • Closure in Loop

    let in the loop can re-binds it to each iteration of the loop, making sure to re-assign it the value from the end of the previous loop iteration, so it can be used to avoid issue with closures.

for (var i = 0; i < 5; ++i) {
  setTimeout(function () {
    console.log(i); // output '5' 5 times
  }, 100);  
}

After replacing var with let

// print 1, 2, 3, 4, 5
for (let i = 0; i < 5; ++i) {
  setTimeout(function () {
    console.log(i); // output 0, 1, 2, 3, 4 
  }, 100);  
}

Should I replace var with let?

NO, let is the new block scoping var. That statement emphasizes that let should replace var only when var was already signaling block scoping stylistically. Otherwise, leave var alone. let improves scoping options in JS, not replaces. var is still a useful signal for variables that are used throughout the function.

let compatibility

  • In server side, such as Node.js, you can safely use the let statement now.

  • In client side, through a transpiler (like Traceur), you can safely use the let statement. Otherwise, please consider the browser support here

Playground

JS Bin on jsbin.com

More info