Recently, I found myself needing to create an array of functions. The functions use values from an XML document, and I am running through the appropriate nodes with a for l
Let's investigate what the code does a little closer and assign imaginary function names:
(function outer(i) {
return function inner() {
return i;
}
})(i);
Here, outer receives an argument i. JavaScript employs function scoping, meaning that each variable exists only within the function it is defined in. i here is defined in outer, and therefore exists in outer (and any scopes enclosed within).
inner contains a reference to the variable i. (Note that it does not redefine i as a parameter or with the var keyword!) JavaScript's scoping rules state that such a reference should be tied to the first enclosing scope, which here is the scope of outer. Therefore, i within inner refers to the same i that was within outer.
Finally, after defining the function outer, we immediately call it, passing it the value i (which is a separate variable, defined in the outermost scope). The value i is enclosed within outer, and its value cannot now be changed by any code within the outermost scope. Thus, when the outermost i is incremented in the for loop, the i within outer keeps the same value.
Remembering that we've actually created a number of anonymous functions, each with its own scope and argument values, it is hopefully clear how it is that each of these anonymous functions retains its own value for i.
Finally, for completeness, let's examine what happened with the original code:
for(var i = 0; i < 10; ++i){
numArr[numArr.length] = i;
funArr[funArr.length] = function(){ return i; };
}
Here, we can see the anonymous function contains a reference to the outermost i. As that value changes, it will be reflected within the anonymous function, which does not retain its own copy of the value in any form. Thus, since i == 10 in the outermost scope at the time that we go and call all of these functions we've created, each function will return the value 10.