2

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.

4 Answers 4

2

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.

Sign up to request clarification or add additional context in comments.

5 Comments

can you explain what your last code do, I need a link to read more.
I've tried to add a little bit more explanation to the end of the answer. Hope that helps.
Thanks! but f[5](); should give 10 in OP code?
In my example f[5]() should give 5 because that's the value of i. f[x]() should always return x (as long as x is between 0 and 9).
The output of f[5]() is 10, not 9.
2

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 iinside 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.

Comments

1

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.

9 Comments

There are NOT 10 copies but only one, which is the entire point.
@JohannesH. I think answer is correct there is 10 copy of same i.
still - that's no copy. All those variables hold references to the same object (an integer in that case), not copies of that object. Copies would be independent of each other. Terminology, sure, but separating both is the key here.
@JohannesH. yes I means and answer means 10 references of same i
I never said there were 10 copies of i, quite the opposite.
|
1

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);
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.