views:

89

answers:

4

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

+1  A: 

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);
}
Kunal
This is not really the problem. Thanks anyway.
Raj
+2  A: 

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);
}
CMS
I think you're missing some braces around your anonymous function expression there.
deceze
@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');} );`
CMS
@deceze: maybe a better example: `var foo = function () { return 'bar'; }();` the function is invoked without problems... `foo === 'bar';`
CMS
Interesting. Thanks for clearing that up.
deceze
A: 

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.

deceze