0

Here my intent is to iterate over an array of elements, and set an event handler on each element while also binding the current iterator value to that event handler. What I've come up with is:

for (var i = 0; i < elementArray.length; ++i)
{
      var elem = elementArray[i];
      elem.onmouseover = function() { foo(i); }
}

function foo(index)
{
       alert(index);
}

Here I use a closure to bind i to foo. The problem is that when foo is actually invoked, i is always equal to elementArray.length, because of course, when foo is invoked i has already been incremented to the maximum value. What I want here, I think, is for a new copy of i to be bound to each anonymous function, so that it passes the correct value to foo. But I'm not sure what the best way to do this is.

Channel72
  • 24,139
  • 32
  • 108
  • 180
  • 1
    No, you don't use a closure, or at least not enough of them :-) The `{ }` of the `for` loop do **not** create a new variable scope. The only thing that does that in JavaScript is a function. – Pointy Feb 22 '12 at 17:08

2 Answers2

1

This isn't working for you because by the time the mouseover handler is invoked, the value of i has changed, it is equal to elementArray.length. What you should do instead is return a function which creates a closure and holds the value of i at the time it is defined.

for (var i = 0; i < elementArray.length; ++i)
{
      var elem = elementArray[i];
      elem.onmouseover = foo(i);
}

function foo(index)
{
    return function(){
       alert(index);
    }
}
driangle
  • 11,601
  • 5
  • 47
  • 54
0

You can use Function.prototype.bind (or define one for the browsers that do not support it) to avoid (explicit) closures. Then your calls would be written as:

elem.onmouseover = function(x) { foo(x); }.bind(this, i); 
Alexander Pavlov
  • 31,598
  • 5
  • 67
  • 93