Well this is a mixed bunch...
You are using the same i
variable (despite "re-defining" it in the second loop, it's still the same i
) that is placed in the global scope
As a result, in the second loop, each iteration alters the value of that global i
, which results in the
function 0
function 1
function 2
function 3
output.
It was, by the way, absolutely not the expected result, if you used k
in the second loop:
<script>
var arr = [];
for(var i = 0; i < 3; i++) {
//Assign anonymous functions to the array in positions 0 to 2
arr[i] = function() { console.log("function " + i); }
}
for(var k = 0; k < 3; k++) {
//The output for these function calls is correct!
arr[k]();
}
//Here I expected to output: function 0, but instead outputs: function 3 WTF!
arr[0] ();
</script>
That would produce:
function 3
function 3
function 3
function 3
and that is the infamous loop problem referred in the link above (in comments).
The reason is that functions, defined in your first loop (which, BTW, you should try to avoid in general case), "close" on the variables that are in the same scope as their definition - i
in this case. That means that whenever value of i
is changed later on, it will be reflected in that function.
The last example shows it in action - i
is changed by the first for
loop, so when the loop is finished - it's value is 3
. All functions you defined now have the same value of i
- 3
.
To make the output like this:
function 0
function 1
function 2
function 0
you can do this (not that it's that great, structure wise):
var arr = [];
for(var i = 0; i < 3; i++) {
//Assign anonymous functions to the array in positions 0 to 2
arr[i] = (function(index){ return function() { console.log("function " + index); };}(i));
}
for(var k = 0; k < 3; k++) {
//The output for these function calls is correct!
arr[k]();
}
//Here I expected to output: function 0, but instead outputs: function 3 WTF!
arr[0] ();
That produces the ddesire result.
Here, you define an anonymous function:
(function(index){ ... }(i))
that is immediately invoked with i
as a parameter. That parameter is referred to as index
in the function body (not that it's important, even if you still called it i
- it would work, since the "inner" i
would shadow the "outer" one).
That function returns a function that has a different closure - on index
, which is not important since index
is not avialable after the immediately invoked function exists.
Another way would be using some sort of iterator - map
, where supported, would do OK.