Properly Scoping Loop Variables
Take the following example:
var foos = ["foo0", "foo1", "foo2"];
for (var i = 0; i < 3; i++) {
var foo = foos[i];
setTimeout(function() {
console.log(foo);
}, 0);
}
You'd think it would print foo0
, foo1
, and foo2
right? Nope. You'll get foo2
three times. This is because foo
inside the closure passed to setTimeout is the same reference.
The timeout calls occur asynchronously, and by the time they do, it's almost certain foo will have reached its final value of foo2
. There are a couple ways around this. One is to use an array in place of foo that stores the values for each iteration separately. This doesn't really make the problem much nicer though.
CoffeeScript's solution is the arcane do
keyword, which creates a new function scope, punning its parameters against the current local scope. For instance, do (i) -> ...
is just (function(i) { ... })(i)
.
Even if you aren't using CoffeeScript, you can solve this problem in the same manner. Just introduce another scope like so:
var foos = ["foo0", "foo1", "foo2"];
for (var i = 0; i < 3; i++) {
(function() {
var foo = foos[i];
setTimeout(function() {
console.log(foo);
}, 0);
})();
}
Now there are multiple foo
variables each within their own scope, with the behavior one would expect coming from a language with block scoping.