0

var funcs=[];
for(var i=0;i<3;i++){

  funcs[i]=function(){
    console.log(i);
    };
  }
for(var j=0;j<3;j++){
  funcs[j]();
  }

In this way ,I know it will alert 3 all.Because the functions were called after i was assigned to 3.

But in the below code, I can't understand why this happens.

for(var i = 0; i < 10; i++) {
    setTimeout(function() {
        console.log(i);
    }, 2000);
}

In my oppinion, when i was assigned to 0, the first function setTimeout would be executed before i was assigned to 1.

Am I wrong in the order of this loop?

zyMacro
  • 675
  • 7
  • 14
  • Possible duplicate of [JavaScript closure inside loops – simple practical example](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – cartant Jan 06 '17 at 03:19
  • You get 3x3 for exactly the same reason. *"the first function setTimeout would be executed before i was assigned to 1."* No, all the functions are executed after the loop has terminated, at which point `i` has the value `3`. The loop doesn't wait for the timeout. And this is actually evident from the fact that you get the output of all 3 functions at *once* 2 seconds in the future. There isn't a 2 sec delay between each output. – Felix Kling Jan 06 '17 at 03:36
  • What do you mean '3x3'? And why 'all the functions are executed after the loop has terminated'? – zyMacro Jan 06 '17 at 05:55

2 Answers2

1

console.log(i) will be called after the for loop finished, the for loop which because of the way var is function scoped. Will be 10 by the time (2000ms) it reaches the console.log statement. One way to give the expected result is using let instead of var. However you are removing some browser support with using let.

Good reading on this topic would be getify's "You Don't Know Js" book.

for(let i = 0; i < 10; i++) {
    setTimeout(function() {
        console.log(i);
    }, 2000);
}
devilfart
  • 351
  • 1
  • 5
  • My question is why"console.log(i) will be called after the for loop finished"? – zyMacro Jan 06 '17 at 05:50
  • The for loop finishes immediately. console.log is inside a `setTimeout`, which will wait before executing. It's happening asynchronously compared to the for loop. `setTimeout` only prevents what's inside of it from executing till the timer is up. Everything outside of it will continue to operate business as usual. – devilfart Jan 06 '17 at 05:57
  • you mean it 'asynchronously' not the setTimeout wait for the loop over? – zyMacro Jan 06 '17 at 06:01
  • `setTimeout` will finish it's timer and execute regardless if the for loop has finished or not, however 2000ms is more than enough time for that for loop to finish incriminating `i`. The code above and before it, runs independently. This sounds like it's more an issue with asynchronous javascript and and how `setTimeout` works than function closures. – devilfart Jan 06 '17 at 06:08
0

You need to put the i variable into a closure, otherwise, it will be rewritten in each loop iteration. The same occurs for the setTimeout function, you should put the i variable into a closure as well.

var funcs=[];
for(var i=0;i<3;i++){

 (function(i){ 
    funcs[i]=function(){
      console.log(i);
    };
  })(i);
}

for(var j=0;j<3;j++){
  funcs[j]();
  }
Pablo Darde
  • 5,844
  • 10
  • 37
  • 55