Reputation: 1052
I was going through a javascript book and have encountered the following code on closure
function constFunc() {
var funcs = [];
for (var i = 0; i < 10; i++) {
funcs[i] = function () {
return i;
}
}
return funcs;
}
var f = constFunc();
f[5]();
The output was not 5. The explanation given was "nested functions do not make private copies of the scope". i would be grateful if could someone explain the above statement.
Upvotes: 2
Views: 287
Reputation: 28528
Here in this loop:
for(var i=0;i<10;i++)
{
funcs[i]=function(){return i;}
}
due to closure, inside function you are accessing parent level variable of i, which after complete loop will be 10. So after loop when you call these function it will return you value of i which is 10.
You can solve it by passing variable as parameter, as parameter create the new copy of variable which maintain its state even on completion of loop.
var myFunctions= [];
function createMyFunction(i) {
return function() {
console.log("My value: " + i);
};
}
for (var i = 0; i < 3; i++) {
myFunctions[i] = createMyFunction(i);
}
Upvotes: 1
Reputation: 165951
When you call constFunc
the loop runs and assigns a function to each element of the funcs
array. Those functions each return the value of i
, which changes on each iteration of the loop from 0
up to 9
.
That means that once constFunc
has finished executing i
will have the value of 9
. When you call one of the functions in the array it returns the value of i
which as we've just seen is now 9
. The value of i
is not captured on each iteration of the loop.
You can force it to be captured via a closure in the loop:
for (var i = 0; i < 10; i++) {
(function (i) {
funcs[i] = function () {
return i;
};
}(i));
}
In this case you are effectively creating a new variable with the same value as i
on every iteration of the loop. You can see that in action here.
By passing i
into a function you end up copying the value of it. So on the first iteration i
has the value 0
. We pass that value into the new function (the argument i
is a different variable to the i
declared in the loop initialiser) and then return that value from the array function. This way, each array function is returning a different i
, instead of each returning the same i
.
Upvotes: 2
Reputation: 943207
There is one variable called i
.
There are 10 functions that return i
.
Each one of those functions returns the current value of the single i
variable.
Upvotes: 1
Reputation: 6167
WHy did you expect the output of 5? RIght, because at the time the function was created, i
was 5. Now, as we can see, the output is not 5 (but, if I didn't miss anything, 9). Now why is that?
The i
inside the closure is not evaluated when the function is created, but when it runs. Now this is where the statement you qoted comes into play: there is only ONE i
- the one created inside constFunc
. All closures work on that one. After constFunc
si done working, that i has, obviously, the value of 9 (becaus that's where the loop stops). SO all closures now output 9.
A simpler example:
function outer () {
var i = 0;
function inner () {
return i;
}
i = 99;
}
outer();
inner(); // <- return 99, not 0.
Upvotes: 2