I searched but couldn't find an answer to this seemingly easy question, so...
Suppose I have a loop in which I need to set callbacks. My callback function looks like this:
function callback(var1) { // code }
Now my loop is something like this:
for( //condition)
{
var x = something_different_each_time;
document.getElementById('foo').addEventListener('click', function() { callback(x); }, false);
}
Now it looks like even if the loop runs n times, the anonymous function is compiled only once -- and hence every invocation of callback is called with the same argument (even though x varies in the loop every time).
I must be missing something here.. any help is greatly appreciated! :)
-
1Similar questions: stackoverflow.com/questions/1734749 stackoverflow.com/questions/643542 stackoverflow.com/questions/1582634 stackoverflow.com/questions/1331769 stackoverflow.com/questions/1552941 stackoverflow.com/questions/750486 stackoverflow.com/questions/933343 stackoverflow.com/questions/1579978 stackoverflow.com/questions/1413916Christian C. Salvadó– Christian C. Salvadó2010年05月21日 07:57:40 +00:00Commented May 21, 2010 at 7:57
-
1that is a comprehensive list @CMS. It would be nice to tag these questions with "closures" and "loops", so they can all be linked with a simple search.Anurag– Anurag2010年05月21日 08:01:56 +00:00Commented May 21, 2010 at 8:01
-
1done, all questions are tagged "javascript", "closures", and "loops". Here's the link - stackoverflow.com/questions/tagged/javascript+closures+loopsAnurag– Anurag2010年05月21日 08:07:50 +00:00Commented May 21, 2010 at 8:07
-
@Anurag, I just visited the SO homepage at the time you started to retag, and thought I had discovered some kind of clever, nefarious hacker as the front page was suddenly full of nearly identical questions by different posters. Then I noticed you were listed as the last active poster on each, and found my way here from the Activity tab on your profile. Joke's on me, but it sure looked fishy at first!eyelidlessness– eyelidlessness2010年05月21日 08:22:00 +00:00Commented May 21, 2010 at 8:22
-
@CMS.. you're welcome. this is a very common issue, nice to have all answers consolidated!Anurag– Anurag2010年05月21日 08:23:20 +00:00Commented May 21, 2010 at 8:23
4 Answers 4
The problem is that the block of the for statement doesn't creates a new scope, for that, the x variable belongs to its enclosing scope, and all anonymous functions refer to the same variable...
Use another function to create a new lexical environment to hold the value of x on each iteration:
for(/*condition*/) {
var x = something_different_each_time;
document.getElementById('foo').addEventListener('click', function () {
return function(y) {
callback(y);
};
}(x), false);
}
3 Comments
(function (fn) { fn();})( function () {alert ('hi');} );var foo = function () { return 'bar'; }(); the function is invoked without problems... foo === 'bar';See Creating closures in loops: A common mistake
and related questions:
Comments
You should calculate x before calling your callback functin!
for( //condition)
{
//var x = something_different_each_time;
document.getElementById('foo').addEventListener('click', function() {
var x = something_different_each_time;
callback(x); }, false);
}
1 Comment
Yes, the x will refer to the same variable in the enclosing scope, and since the function is executing later, it'll have the last value of x. Try this:
.addEventListener(
'click',
(function (i) {
return function () { callback(i); }
})(x),
false
);
This creates a closure with the current value of x locked inside.