-1

I came across the following interview question:

var arr = [ 10, 12, 15, 21 ];

for(var i = 0; i < arr.length; i++) {
  //console.log('outside timeout ' + i)
  setTimeout(function(){
    console.log('Index: ' + i + ', element: ' + arr[i])
  }, 3000)
}

by the time setTimeout runs the loop has finished running. But, how does i inside the setTimeout outputs 4? Shouldn't it stop at 3?

https://codepen.io/AlexanderWeb00/pen/vjXmBo

Aessandro
  • 5,517
  • 21
  • 66
  • 139
  • Duplicate of https://stackoverflow.com/questions/49958556/why-does-settimeout-behave-incorrectly-inside-a-for-loop. It is only touching a `closure`. @Satpal – deEr. Apr 27 '18 at 10:59
  • @Alex I I had given answer first... – Parth Raval Apr 27 '18 at 11:25
  • at the end, the value of the variable is always greater than the last value to be true in the check, because this works as exit condition after the last increment. it has nothing to do with the timeout. the timeout uses the last value, because oof the value at the time where the timeout is calling the function. – Nina Scholz Apr 27 '18 at 12:14

1 Answers1

2

Wrap setTimeout around an IIFE

var arr = [ 10, 12, 15, 21 ];

for(var i = 0; i < arr.length; i++) {
  //console.log('outside timeout ' + i)
  (function(i){
        setTimeout(function(){
           console.log('Index: ' + i + ', element: ' + arr[i])
        }, 3000)
    })(i);
}

Reasoning - var are functional scope variables and even if specified in a if/for/while will be available in the whole function. The condition governs the number of times the loop will run, which over here breaks when i becomes 4. However, when the timeout function is executed for the i=0 or i=1 and others, i has already reached 4 as it has completed the for loop. Hence, you need to explicitly pass the value of i using an IIFE.

Also, if you are using ES6 and above, you can use let also specified by Satpal in comments.

var arr = [ 10, 12, 15, 21 ];

for(let i = 0; i < arr.length; i++) {
  //console.log('outside timeout ' + i)
  setTimeout(function(){
    console.log('Index: ' + i + ', element: ' + arr[i])
  }, 3000)
}
Nikhil Aggarwal
  • 28,197
  • 4
  • 43
  • 59