Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Javascript Closures: Understanding difference between let and var with an example [duplicate]

Although i understand that let allows you to declare variables that are limited in scope to the block, I encountered a strange difference between let and var while using it with javascript closures. Here is my example:

With let:

function buildFunction() {

  var arr = [];
  for(var i = 0; i < 3; i++) {
    let j = i;  //Using let to assign j
    arr.push(
      function(){
        console.log(j);
      }
    )
  }
   return arr;
}

var fs = buildFunction();
fs[0]();
fs[1]();
fs[2]();

The above code snippet outputs:

0
1
2

With var:

function buildFunction() {

  var arr = [];
  for(var i = 0; i < 3; i++) {
    var j = i;  //Using var to assign j
    arr.push(
      function(){
        console.log(j);
      }
    )
  }
   return arr;
}

var fs = buildFunction();
fs[0]();
fs[1]();
fs[2]();

The above code snippet outputs the following:

2
2
2

My question is:

  1. If U am using var inside a block and assigning it a value during execution, shouldn't it work exactly like let and store different copies of j in memory ?

  2. Does javascript handle let and var differently within a closure ?

Any clarifications on this would be highly appreciated.

like image 528
g.005 Avatar asked Jun 16 '26 10:06

g.005


1 Answers

var scopes to the function; let scopes to a block of code.

In your example j is scoped to the function buildFunction() when you use var. This means your using the 'same' j in every function. When your for loop runs j is set to 0, then 1, then 2. When you then run the console logs your referencing the j that was set to 2, so you get 2 2 2.

When you use let, you scope j to that iteration of the for loop. This means every iteration has a 'different' j, and the console logs print what you expect them to print.

If you were using ES5 and needed to use var, you could replicate the let effect (have it print 0 1 2), by wrapping your original anonymous function with a self-executing function and passed j in as an argument. This would create a new scope for j in the self-executing function whose value is the value of j in the current iteration.

function buildFunction() {

  var arr = [];
  for(var i = 0; i < 3; i++) {
    var j = i;  //Using var to assign j
    arr.push(
      //self executing function
      (function(j) { //j here is scoped to the self executing function and has the value of j when it was called in the loop. Any changes to j here will not affect the j scope outside this function, and any changes to j outside this function will not affect the j scoped inside this function.
        //original function
        return function() {
          console.log(j);
        }
      })(j) //call with the value of j in this iteration
    )
  }

  return arr;
}

var fs = buildFunction();
fs[0]();
fs[1]();
fs[2]();
like image 120
Nick Freitas Avatar answered Jun 19 '26 01:06

Nick Freitas