musings of a Lispnik

Daniel Janus's blog

A quirk with JavaScript closures

| Comments

I keep running into this obstacle every now and then. Consider this example:

1
2
3
4
5
6
> q = []
[]
> for (var i = 0; i < 3; i++)
    q.push(function() { console.log(i); });
> q[0]()
3

I wanted an array of three closures, each printing a different number to the console when called. Instead, each prints 3 (or, rather, whatever the value of the variable i happens to be).

I am not exactly sure about the reason, but presumably this happens because the i in each lambda refers to the variable i itself, not to its binding from the creation time of the function.

One solution is to enforce the bindings explicitly on each iteration, like this:

1
2
3
4
for (var i = 0; i < 3; i++)
  (function(v) {
    q.push(function() { console.log(v); });
  })(i);

Or use Underscore.js, which is what I actually do:

1
2
3
_([1,2,3]).each(function(i) {
  q.push(function() { console.log(i); });
});

Comments