Sameer Sarmah
Sameer Sarmah

Reputation: 1052

javascript function closure working

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

Answers (4)

Zaheer Ahmed
Zaheer Ahmed

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

James Allardice
James Allardice

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

Quentin
Quentin

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

Johannes H.
Johannes H.

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

Upvotes: 2

Related Questions