简体   繁体   中英

A JavaScript closure confusion

→ jsFiddle

function f1(){
    var n=999;

    nAdd=function(){n+=1;};

    function f2(){
        alert(n);
    }
    return f2;
}

var result = f1();
var result2 = f1();

result();  // 999
nAdd();
result2(); // 1000
result2(); // 1000
result();  // 999

I am trying to learn JavaScript closures, but the code above just got me confused. When the first time result() is called , it's 999. That's ok for me.

After nAdd() is called, result2() shows 1000. And I think this is due to function result2() and function result() are equals to function f1() .

But why does the last result() show 999 instead of 1000?

Each time f1() is called that creates a new closure with its own local n variable.

However, the nAdd variable is global, and so gets overwritten every time f1() is called - which means calling nAdd() will only ever add to the n variable in the last closure.

UPDATE: If you want to be able to increment the values of n in each closure independently you could do something like this:

function f1(){
    var n=999;
    return {
        incrementN : function(){n+=1;},
        getN : function f2(){console.log(n);}
    }
}    
var result = f1();
var result2 = f1();
result.getN(); // 999
result.incrementN();
result2.getN();//999
result2.incrementN();
result2.getN();//1000
result.getN();//1000

That is, have f1() return an object containing two methods that are not declared as globals, and that both operate on the local n variable from the closure they belong to.

There're already good answers, but I guess a picture would be helpful to understand.

在此输入图像描述

Each time you call f1() you:

  • Create a new (local) variable called n with a value of 999
  • Create a new nameless function assigned to the global nAdd that modifies that n (and overwrites any previous function assigned to nAdd )
  • Create a new function that you return which alerts the value of that n

You call f1() twice, so you do all that of that twice. The second time you call it, you overwrite nAdd with a new function that modifies the second n .

This leaves you with:

  • result() which alerts the first n
  • result2() which alerts the second n
  • nAdd() which increments the second n

result() on the last line alerts 999 because it alerts the value of the first n (which has never been incremented).

result and result2 contain the result of different invocations of f1 and hence contain different instances of the local variable n . Each invocation of a function may have different values for the local variables of that function. That does even apply when no closures are involved.

The nAdd=function(){n+=1;}; line creates a global function which is a closure inside f1() . A closure has access too all variables from scope of the function which created it. So each time you call f1() it creates a new nAdd() function which has n value bound to value of var n of the call of f1() .

In your code;

var result = f1();
var result2 = f1();
result(); // 999
nAdd();         // Created by "var result2 = f1();" and has the same 'n' value as function in result2
result2();//1000
result2();//1000
result();//999

the result and result2 create two different closures with different n. If you make na global variable by declaring it outside of the f1() function, then you will get the result that you had expected since in that case you will always be accessing the global variable n:

var n=999; function f1(){
nAdd=function(){n+=1;};
function f2(){
console.log(n);
}
return f2;
}
var result = f1();
var result2 = f1();
result(); // 999
nAdd();
result2();//1000
result2();//1000
result();//1000

it like that:

var nAdd;
function f1(){
    var n=999;

    nAdd=function(){n+=1;};

    function f2(){
        alert(n);
    }
    return f2;
}

var result = f1();//var nAdd=function(){n+=1;} n=result.n=999

var result2 = f1();//var nAdd=function(){n+=1;} n=result2.n=999

var result3 = f1();//var nAdd=function(){n+=1;} n=result3.n=999

nAdd();

result();  // 999

result2(); // 999

result3(); // 1000

var result = f1();//var nAdd=function(){n+=1;} n=result.n=999

var result2 = f1();//var nAdd=function(){n+=1;} n=result2.n=999

nAdd();

var result3 = f1();//var nAdd=function(){n+=1;} n=result3.n=999


result();  // 999

result2(); // 1000

result3(); // 999

var result = f1();//var nAdd=function(){n+=1;} n=result.n=999

var result2 = f1();//var nAdd=function(){n+=1;} n=result2.n=999

nAdd();

var result3 = f1();//var nAdd=function(){n+=1;} n=result3.n=999
nAdd(); 
nAdd();
nAdd();   

result();  // 999

result2(); // 1000

result3(); // 1002

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