简体   繁体   中英

javascript closure ,who can help me to understand why

var functions = [];
(function foo() {

    for (var i=0; i<5; i++ ) { 
        var f = function() {
            console.log(i);
        }
        functions.push(f);
    }

    for (var i=0; i<5; i++ ) { 
        f = new Function("console.log(i);");
        functions.push(f);
    }

})();

for (var i=0; i<10; i++ ) { 
    functions[i]();
}

the output is :

5 5 5 5 5 5 6 7 8 9

can anybody help me sort out the flow?

first of all you should know whenever you want to run this function:

Function("console.log(i);");

this would use the current context's i variable as its value. so you might want to do:

var functions = [];
(function foo() {

    for (var i = 0; i < 5; i++) {
        var f = function func() {
            console.log(func._i);
        };
        f._i = i;
        functions.push(f);
    }

    for (var i = 0; i < 5; i++) {
        f = new Function("console.log(" + i + ");");
        functions.push(f);
    }

})();

for (var i = 0; i < 10; i++) {
    functions[i]();
}

I changed it this way and my result is:

0, 1, 2, 3, 4, 5, 6, 7 ,8, 9

Why is that?

1- all of the functions in your first for loop use a single variable i , and as its last value is 5 then all would print 5.

2- the other ones which get created in your second for loop, whenever they get invoked they would use the i variable in their current context, and as far as they get invoked in your last for loop, they use the i variable in the loop, to make it clear. you can easily change your last for loop like this:

for (var j = 0; j < 10; j++) {
    functions[j]();
}

and as there is no i variable in the context (I changed it to j ), then your output would be:

5 5 5 5 5 undefined undefined undefined undefined undefined

undefined is there because function can not fin any i variable in the context.

It's actually printing out five 5's and then 5, 6, 7, 8, 9. The first five 5's are from var i in that for loop, the functions save a reference to that var i and access it when you run it, and since it equals 5 at the end of the for loop, they all return 5. The second set of numbers comes from the quoted function accessing i from the for loop there, ergo it printing out 5, 6, 7, 8, 9.

Lots of good answers here: How do JavaScript closures work?

The first 'for' loop is generating 5 functions each of them creates a closure which captures the 'i' as 5 (last value of 5 for that loop after last increment) so they all render out 5 (it just shows in Chrome as the first 5 with 5 in a circle next to it meaning the same value was logged out 5 times)

The second 'for' loop generates functions that will use 'i' from the scope it executes from, in this case the scope is the 3rd 'for' loop...

Closure allow you to access the variable from parent scope, which sometime cause strange or wrong behavior, here in this scenario closure is causing the output: 5 5 5 5 5 0 1 2 3 4

I am trying this code with:

f = new Function("alert("+i+");");

In first loop:

 for (var i = 0; i < 5; i++) {
    var f = function func() {
        console.log(func._i);
    };
    f._i = i;
    functions.push(f);
 }

you are referencing i of parent means loop variable, so five different functions are created all with the same copy of variable i, which is changing with iteration, at the end of loop where condition break is i=5 since all functions are referencing the same copy, so change to original copy will effect all. So each function now has the i=5

Now in second loop, you are appending it as a string, which doesn't refer to original copy but creating a new string for each iteration:

for (var i = 0; i < 5; i++) {
  f = new Function("console.log("+i+");");
  functions.push(f);
}

this create five different functions with each different string:

console.log("0");
console.log("1");
console.log("2");
console.log("3");
console.log("4");

Now calling each function created by loop1 functions[0] to functions[4] is referring the same copy of i will print 5 while second functions[5] to end has there own strings to print.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM