Each alert call is being passed the same copyindex variable, even though a new one is being declared each time...
That's a common misunderstanding. var
does not have block scope, so your code really is this:
var copyindex;
for (var myindex = 0; myindex < mylist.length; myindex += 1) {
copyindex = myindex;
MyAsync(mylist[myindex], function () { alert(copyindex); });
}
More (on my blog): Poor, misunderstood var
and, of course, in the specification — it's covered in §10.5 - Declaration Binding Instantiation.
ES6 will introduce block-scoped variables via the let
keyword. Where you use the let
keyword matters quite a lot.
Let's take a simpler example, starting with var
:
for (var x = 0; x < 3; ++x) {
setTimeout(function() { console.log("x = " + x); }, 0);
}
console.log("typeof x = " + typeof x);
We know that will give us
number
3
3
3
...because var
is hoisted to the top of the scope, and so the same x
is used by all three functions we create, and x
exists outside the loop. (We see the typeof
result first, of course, because the others happen after the minimal timeout.)
If we use let
instead, in that same place:
for (let x = 0; x < 3; ++x) {
setTimeout(function() { console.log("x = " + x); }, 0);
}
console.log("typeof x = " + typeof x);
We get
undefined
3
3
3
...because x
is scoped to the loop, not loop iterations. All three functions still use the same x
, the only difference is that x
doesn't exist outside the loop.
But if we use let
within the body:
for (let n = 0; n < 3; ++n) {
let x = n;
setTimeout(function() { console.log("x = " + x); }, 0);
}
console.log("typeof x = " + typeof x);
We get
undefined
0
1
2
...because now x
is scoped to the body of each iteration, not the loop as a whole.
You can try these yourself using NodeJS, just be sure to give it the --harmony
flag to enable ES6 features.