Closures, for loops and scoping in JavaScript
var funcs = []; for (var i = 0; i < 10; i++) { funcs.push( function() { console.log(i) } ); }
What does funcs[0]()
output?
If you said 10, you were right.
The key here is that although i
is accessible from the scope of the closure, it can be modified by other things. The closure doesn't copy the values it can access when it's created.
In some cases, this kind of thing does work as expected. That's because in those cases, you are accessing a value that doesn't change. Even though it looks like it might have. If you combine with a forEach function, you actually get your own value that won't change.
You can also do this by creating a copy inside a function expression:
var funcs = []; for (var i = 0; i < 10; i++) { (function(i) { funcs.push( function() { console.log(i) } ); }(i)); }
funcs[0]()
=> 0.
Note that the i
accessible within the closure is a different i
from the for loop's.
If you're using any helper libraries (or Node) with your for loops you don't need to run into this too often. The above is equivalent to:
var funcs = []; [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(function(i) { funcs.push( function() { console.log(i) } ); });
Talk is cheap