Yeah I know how this stuff works per spec.You say that, and yet, you seem not to understand it. Perhaps you know how it works, but have not thought through the implications of it working any differently?
No, closures refer to the j variable that doesn't get incremented, only assigned to. ... The actual issue is that all invocations of the loop body alias the same var j, even though it's declared inside the block.
You're doing it wrong. Javascript doesn't have block-level scope. It only has functional scope.
In the process of parsing an execution context, all "var" statements (and named function declaration statements, which are a special sort of "var") are handled first, and only once. A var inside a loop still only creates the variable once, scoped to the function.
So, your code sample is actually equivalent to:
var closures = [], j = undefined;
for (var i = 0; i < 10; i++) {
j = i;
closures[i] = function() { alert(j); }
}
closures[0](); // outputs 9, duh ;)
You have one "j" variable that is shared by all 10 closures. When you set "j" in loop iteration 9, the closure created in iteration 0 faithfully sees that change.
Closures tracking changes to variables in the parent function is not a wart. Consider this code:
var thing = (function () {
var privateData = "foo";
return {
set : function (x) { privateData = x; },
get : function () { return privateData; }
};
})();
If closures "trapped" outer values at their current state, then no matter how you called thing.set(), it would always return "foo" from thing.get(). Also, it would be much more expensive to keep track of completely independent contexts.
(You could argue that these side effects make js a less pure functional language, and you'd be correct; another, less clear, argument could be made that this makes javascript less good, and I'd disagree.)However, your complaint seems not to be about closures or shared activation objects per se, but rather about the lack of block-level scope. Since "j" is created inside a set of braces, you seem to suggest that there ought to be multiple "j" variables created, which are each forgotten at the end of the loop.
That's how C++ does it. But javascript is not C++. Javascript is javascript. And only functions create scope in javascript.
IMO, this is not a wart. Doing otherwise would mean that every "while", "for", "switch", "if", and "else" would have to create an activation object, which would get quite expensive and complicated.
If you find it confusing that a var inside a loop is only created once, then take Crockford's advice, and always put all "var" statements at the start of a function. Personally, I disagree with him on this point, because I find it more useful to "var" variables near their use so that moving code around doesn't accidentally result in leakage to the global scope.