1

I don't understand how to explain the below code and why it does not work as intended:

for (var i = 0; i < 16; i++) {

    setTimeout(function () {
        console.log(i);
    }, 1)

}

// Prints "16" 16 times

One solution to this would be simply using let instead of var in the for loop, or

for (var i = 0; i < 16; i++) {

    (function (k) {
        setTimeout(function () {
            console.log(k);
        }, 100)
    })(i)
}

// Print "0" to "15"

a self invoking function.

If I could have an educated guess to this it would be that var's scope is tied to the function block, or in the case the global scope, and the for loops will beat the call stack that the setTimeout() will produce and since Javascript is lexically scoped it calls back all these functions as var i = 16 where on the other hand let i = 16 will keep it to the block?

James Marino
  • 668
  • 1
  • 9
  • 25

1 Answers1

0

In the first example, you have a closure around the looping variable i. In the second, you avoid that by making a copy of i and instead using k. Avoiding the closure allows each iteration to keep its own value instead of sharing i with all the iterations. Using let would also solve the issue because it would make the looping variable i, have block level scope and that would mean that upon each iteration, i would technically be a different variable than the previous one, so each nested function would be gaining a reference to a different value.

This is all because of how scope in JavaScript works and how nested functions lead to closures, which has side-effects on code when the nested function references variables from a higher order function AND the nested function has a longer life than the parent. In your case the function referenced by setTimeout will live longer than its containing function.

Scott Marcus
  • 64,069
  • 6
  • 49
  • 71