2

Possible Duplicates:
Javascript closure inside loops - simple practical example
Javascript closure “stores” value at the wrong time

for (var i = 1; i <= 3; ++i) {
    setTimeout(function() {
        alert(i);
    }, i * 1000);
}

This alerts "4" 3 times. I know why, but I won't spoil it here... although I forgot how to fix it. What's a concise way of solving this problem?

Community
  • 1
  • 1
mpen
  • 272,448
  • 266
  • 850
  • 1,236
  • What problem, exactly, are you attempting to solve? – g.d.d.c Oct 28 '10 at 01:57
  • 2
    possible duplicate of [Javascript closure inside loops - simple practical example](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) and pretty much everything on [javascript+loops+closures](http://stackoverflow.com/questions/tagged/javascript+loops+closures). – Josh Lee Oct 28 '10 at 01:57
  • Duplication of http://stackoverflow.com/questions/2037203/javascript-using-settimeout-in-for-in-loop. You're in a tight loop, so you don't have many options. – Jason McCreary Oct 28 '10 at 02:09
  • @gddc: a very similar one to this... I want to use setTimeout to call a function, and I want to pass a variable into that function, but I want the variable "copied". – mpen Oct 28 '10 at 02:50

2 Answers2

5
for (var i = 1; i <= 3; ++i) {
    setTimeout((function (x) {
        return function () { alert(x); }
    })(i), i * 1000);
}
deceze
  • 510,633
  • 85
  • 743
  • 889
  • 1
    @rchern I wouldn't mind, but this has been explained a [thousand times over](http://stackoverflow.com/questions/tagged/javascript+loops+closures) already and this question seems destined for quick closure (pun intended) as duplicate of one of these. Also, the OP seems to understand the problem, he was just looking for the syntax. – deceze Oct 28 '10 at 02:01
  • @rchern Why not? Isn't half an answer better than no answer? *shrugs* :) – deceze Oct 28 '10 at 02:09
  • @deceze: But a full answer is still better than a half answer. – BrunoLM Oct 28 '10 at 02:10
  • @Bruno But a full answer seemed like a waste of time, since it won't serve anybody in the future, since the question is now closed. Sorry for providing half-assed help. The weather is bad, okay? ;o) – deceze Oct 28 '10 at 02:12
  • I don't understand answering a question you're voting to close as a dupe. Isn't it contradictory? – Rebecca Chernoff Oct 28 '10 at 02:29
  • @rchern Closing is a long-term clean up/maintenance thing, it doesn't mean I can't also give the OP a direct answer which helps him immediately. – deceze Oct 28 '10 at 02:36
  • Thanks deceze :) That's correct, I didn't need an explanation of closures... I just forgot what syntax to use. I knew I could create one by creating an anonymous function and calling it immediately, but the part I was forgetting was that I needed to return a new function. – mpen Oct 28 '10 at 02:45
  • @everybody There you go. Awesome, -2 on a correct and accepted answer. Is there a badge for that? :o) – deceze Oct 28 '10 at 02:46
  • I think I solved this before by putting the closure around the `setTimeout` and without the return.. I was trying to put it inside the `setTimeout` this time and it wasn't working. – mpen Oct 28 '10 at 02:47
4

That is a very common issue. With JS 1.7 this is easily solved using let keyword. To check browser version equivalency click here.

You can workaround this using closures. Create a scope for i and return the function for setTimeout.

for (var i = 1; i <= 3; ++i) {
    setTimeout((function(i) { /* i is now a parameter */
        return function () { /* this function is the one that will execute */
            alert(i); /* this `i` is not the same as the one used on the loop */
        }
    })(i), i * 1000);
}
BrunoLM
  • 97,872
  • 84
  • 296
  • 452