Check out the following snippet of HTML/Javascript code:
<html>
<head>
<script type="text/javascript">
var alerts = [];
for(var i = 0; i < 3; i++) {
alerts.push(function() { document.write(i + ', '); });
}
for (var j = 0; j < 3; j++) {
(alerts[j])();
}
for (var i = 0; i < 3; i++) {
(alerts[i])();
}
</script>
</head><body></body></html>
This outputs:
3, 3, 3, 0, 1, 2
which isn’t what I was expecting – I was expecting the output 0, 1, 2, 0, 1, 2,
I (incorrectly) assumed that the anonymous function being pushed into the array would behave as a closure, capturing the value of i that’s assigned when the function is created – but it actually appears that i is behaving as a global variable.
Can anyone explain what’s happening to the scope of i in this code example, and why the anonymous function isn’t capturing its value?
In Javasript, the only “interesting” lexical scope boundary is the function body. Anything declared anywhere in a function (well, anywhere other than another nested function!) is at the same scope. There are also some weird things about the way that the declarations are interpreted.
Your anonymous function does act as a closure, but each function instantiated will share the same “i”. A trick I use is to add another layer of function:
At somepoint hopefully all the browsers will support the new “let” statement, which is a shorter, less weird-looking way to do basically the same thing.