0

I have been trying to understand why the following code snippet behaves as it does:

    for (var i=1; i<=5; i++) {
        setTimeout( function timer(){
            console.log( i );
        }, i*1000 );
    }  //prints 6 five times with a gap of one second in between each

Why the 6? I have seen some explanations but I still couldn't understand. Also why does the code below work?

    for (var i=1; i<=5; i++) {
        (function(){
            var j = i;
            setTimeout( function timer(){
                console.log( j );
            }, j*1000 );
        })();
    }
  • The second code fragment creates a copy of `i` in each loop, so when the timeout actually triggers you see the preserved state of `i`. The first example always references the same `i`, hence when the timeout finally triggers, they all show the final value of `i`. – Sirko Jun 13 '17 at 18:46

1 Answers1

0

You're passing setTimeout() the same lambda five times, each time with a reference to the same loop variable, i. For each call, the lambda is evaluated after the loop exits, when i is equal to 6 (i++, check if i <= 5, if not, break out of the loop).

The lambda has a reference to the variable itself, not to its value at the time the lambda was created. That's very useful in most cases. Just not this one.

The var j; version has two lambdas. The one with var j = i; is executed immediately, with the current value of i. That creates a new variable j, local to that lambda. j is initialized with the value of i that was current at the time the outer lambda was executed. So in that case, you're giving setTimeout() what you may as well consider five different lambdas, with five different variables, all named j, but with five different values.

The inner lambda is executed later, but it uses j.

What differs is the code has created a unique location to store each value of i.

Final point: In some other languages, this would work:

for (var i=1; i<=5; i++) {
    var j = i;
    setTimeout( function timer(){
        console.log( j );
    }, j*1000 );

}

In JavaScript, it does not. The scope of j differs. In JavaScript, there will only be one j in that case. That's why the immediately executed function is used: To ensure that there will be more than one j.