function f1(){
var n = 999;
nAdd = function(){ n += 1;}
function f2(){
alert(n);
}
return f2;
}
這里的閉包是 f1,封閉了一個(gè)變量 n 和一個(gè)函數(shù) f2。
我們先無視 nAdd,盡量保持原貌重寫一下這個(gè)函數(shù)。
function f1(){
var n = 999;
var f2 = function(){ alert(n); };
return f2;
}
var result = f1();
result();
js 中各個(gè)變量以 function 為單元進(jìn)行封裝,當(dāng)在 function 內(nèi)部找不到某一變量時(shí),function 會向其所在的上一單元(上下文)中進(jìn)行查找,一直查找到頂層的 window 域。
這時(shí)就出現(xiàn)一個(gè)疑問:這個(gè)查找過程是以函數(shù)引用位置為起點(diǎn)還是函數(shù)體定義的位置為起點(diǎn)?
在上面這一段代碼中,result 所在域是 window,但是實(shí)際的輸出結(jié)果是 f1 內(nèi)部的 n 值,所以可以得出結(jié)論:變量查找的起點(diǎn)是函數(shù)體定義的位置。
現(xiàn)在再回過頭來看 nAdd(第一段代碼)。如我們所知,沒有關(guān)鍵字 var 定義的變量默認(rèn)進(jìn)入 window 域,所以 nAdd 實(shí)際為 window.nAdd。這就等同于如下代碼:
var nAdd;
function f1(){
var n = 999;
nAdd = function(){ n += 1;}
function f2(){
alert(n);
}
return function(){ alert(n); };
}
那么根據(jù)我們對 result 的分析,nAdd 的執(zhí)行將影響 f1 中 n 的值。
所以有:
function f1(){
var n = 999;
nAdd = function(){ n += 1;}
function f2(){
alert(n);
}
return function(){ alert(n); };
}
var result = f1();
result();
nAdd();
result();
這段代碼執(zhí)行最終的輸出結(jié)果為 1000。
再看這種情況:
function f1(){
var n = 999;
nAdd = function(){ n += 1;}
function f2(){
alert(n);
}
return function(){ alert(n); };
}
f1()(); //<--p1
nAdd();
f1()(); //<--p2
簡述一下執(zhí)行過程:
p1 位置,f1 封裝了一個(gè)匿名的閉包 A,在返回 A 閉包中的函數(shù) A:f2 后繼而執(zhí)行 A:f2,A:f2 輸出變量 A:n,結(jié)果是 999。
與此同時(shí),nAdd 被賦值為 A 閉包中的一個(gè)函數(shù),下一行執(zhí)行 nAdd 即讓 A:n 的值 + 1。
p2 位置,f1 封裝匿名的閉包 B,所進(jìn)行的操作都是針對閉包 B 的,隨后執(zhí)行 B:f2 輸出的是 B:n,所以最后的結(jié)果依然是 999。
A 和 B 是兩個(gè)獨(dú)立的 “包”,互不影響。
改寫一下函數(shù)的調(diào)用部分:
[js] view plaincopy
function f1(){
var n = 999;
nAdd = function(){ n += 1;}
function f2(){
alert(n);
}
return function(){ alert(n); };
}
var result = f1();
result();
nAdd();
f1()();
result(); // <--p3
p3 位置不意外地輸出了 1000。