4

on a website i want to do this: (simplified)

myHandlers = new Array();
for(var i = 0; i < 7; i++) {
  myHandlers.push(new Handler({
    handlerName: 'myHandler'+i, // works, e.g. ->myHandler1, 2, 3 etc.
    handlerFunc: function(bla) { /*...*/ alert(i); } // doesn't work,all return 7
  }
}

I could set the counter as another attribute of my Handler (which would copy the current value) and use it inside my function, but I guess, there is also a way to actually copy this value, no?

Fabian Fritz
  • 390
  • 3
  • 14
  • http://stackoverflow.com/questions/3443902/bind-different-functions-for-just-created-li-elements – Marko Dumic Aug 10 '10 at 11:17
  • possible duplicate of [Javascript closure inside loops - simple practical example](http://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example) – rds Feb 01 '13 at 09:28

3 Answers3

6

When handlerFunc is called, the i inside the function refers to the i of the for loop. But that i does probably not have the same value any more.

Use a closure to bind the current value of i in the scope of an anonymous function:

handlerFunc: (function(i) { return function(bla) { /*...*/ alert(i); }; })(i)

Here an anonymous function (function(i) { … })(i) is used and called immediately. This function binds the value of i of the for loop to the local i. That i is then independent from the i of the for loop.

Gumbo
  • 643,351
  • 109
  • 780
  • 844
2
var myHandlers = new Array();
for (var i = 0; i < 7; i++) {
  myHandlers.push(new Handler({
    handlerName: 'myHandler'+i, // works, e.g. ->myHandler1, 2, 3 etc.
    handlerFunc: 
    (function(i) { 
     return function(blah) { 
         alert(i) 
     }
     })(i)
  }))
}

Use a closure to bind the i so the value stays intact

meder omuraliev
  • 183,342
  • 71
  • 393
  • 434
2

In your example, i in the functions is the same variable as i outside the functions. As i is incremented in the loop, so is it incremented within the functions. As a result, if the functions are called after the loop has finished, they will all alert "7".

You need to create a new variable with appropriate scope and copy the value of i into it.

Something like this would create the desired effect.

...
var pushHandler = function(i) {
  myHandlers.push(new Handler({
    handlerName: 'myHandler'+i, // works, e.g. ->myHandler1, 2, 3 etc.
    handlerFunc: function(bla) { /*...*/ alert(i); } // doesn't work,all return 7
  }
}
...
for(var i = 0; i < 7; i++) {
  pushHandler(i);
}

...
Paul Butcher
  • 6,902
  • 28
  • 39
  • Sorry to comment on this 6 years after the fact, but I just came across this problem while writing some node. I prefer this method, as (at least for me) is much more understandable than the above method of pushing an interpreted method passing in `i`. I'm still having trouble wrapping my head around the whole thing. This is very simple, concise, and understandable. – SpacePope Aug 14 '16 at 22:59