1

I was going through an Advanced JavaScript text and came across these codes, I think the writer was trying to demonstrate closures but didn't explain the codes. I've been staring at these sets of codes for hours and still can't figure out why they will produce different output.

for (var i = 0; i <= 2000; i += 1000) {
    setTimeout(function () {
      console.log('i value in closure is ' + i);
    }, i);
}
//Output
// i value in closure is 2000
// i value in closure is 2000
// i value in closure is 2000`

and

for (var i = 0; i <= 2000; i += 1000) { 
  (function (i) { 
    setTimeout(function () { 
      console.log('i value in closure is ' + i); 
    }, i); 
  })(i); 
}
//Output
// i value in closure is 0
// i value in closure is 1000 
// i value in closure is 2000`
Bartłomiej Semańczyk
  • 59,234
  • 49
  • 233
  • 358

1 Answers1

2

In the first code block, the for loop will run to completion. Each time through the loop will schedule a setTimeout() call for some time in the future. But, when that setTimeout() actually fires, the value of i will be the value at the END of the for loop for all the setTimeout() calls.

In the second code block, the for loop will again run to completion, but each time through the for loop it creates a new function closure that "captures" the value if i separately for each timer callback and thus it will display the desired value of i inside the setTimeout() callback because it has been saved separately for each timer.

You can think of your second code more like this:

function myTimer(index) {
    setTimeout(function () { 
      console.log('i value in closure is ' + index); 
    }, index); 
}

for (var i = 0; i <= 2000; i += 1000) { 
    myTimer(i);
}

The only difference between your second code block and this expanded code here is that your second code block uses an anonmymous IIFE instead of the named myTimer() function shown here, but the execution is the same. The use of this function inside the for loop creates a Javascript function closure that saves the value of i so that when the setTimeout() calls its callback later, that unique value of i is available to the callback and it does this for each invocation of that function.

The construction:

  (function (i) { 
      some async operation here that uses i
  })(i);   

is called an immediately invoked function expression (abbreviated IIFE) and is a quick way to create a closure in Javascript.

See this prior answer for more info on the topic: Asynchronous Process inside a javascript for loop

Community
  • 1
  • 1
jfriend00
  • 683,504
  • 96
  • 985
  • 979