1

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! :)

10

4 Answers 4

2

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);
}
Sign up to request clarification or add additional context in comments.

3 Comments

I think you're missing some braces around your anonymous function expression there.
@deceze: Nope, the parentheses are required only when the function is on a place where it can cause a grammatical ambiguity between a function expression and a function declaration, in this case, the function is in the arguments list of a function call, it's clearly on expression context, no ambiguity... e.g.: (function (fn) { fn();})( function () {alert ('hi');} );
@deceze: maybe a better example: var foo = function () { return 'bar'; }(); the function is invoked without problems... foo === 'bar';
2

See Creating closures in loops: A common mistake

and related questions:

Comments

1

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

This is not really the problem. Thanks anyway.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.