本文參考博客:
1. http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html
2.https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures (官方的)
第一步:理解鏈式作用域
答:Javascript語言的特殊之處,就在于函數內部可以直接讀取全局變量。 不同于塊級作用域哦!
function f1(){
var n=999;
function f2(){
alert(n); // 999
}
}
如上,函數f2就被包括在函數f1內部,這時f1內部的所有局部變量,對f2都是可見的。但是反過來就不行,f2內部的局部變量,對f1就是不可見的。這就是Javascript語言特有的"鏈式作用域"結構(chain scope),子對象會一級一級地向上尋找所有父對象的變量。所以,父對象的所有變量,對子對象都是可見的,反之則不成立。
第二: 對于阮老師博客的理解補充
阮老師在閉包博客中說:它的最大用處有兩個,一個是前面提到的可以讀取函數內部的變量,另一個就是讓這些變量的值始終保持在內存中。
第一點是認同的,但第二點有點不敢茍同(初生牛犢,如有錯誤,還請大神留言指教)。
阮老師的js代碼:
function f1(){
var n=999;
nAdd=function(){n+=1} // 全局變量
function f2(){ // 局部變量
alert(n);
}
return f2;
}
var result=f1(); // 因為這里改變了f2的作用域,所以f2才一直在內存中。 作用域由(f1()內部變量 ——》f1()平級)。
result(); // 999
nAdd(); // 由結果看,下面的值為1000,說明nAdd() 執行了, 因為f2作用域被改變后就一直在內存中,所以f1也一直在內存中。
result(); // 1000
// 我如果這樣寫,換一種方式調用,不改變f2的作用域
f1()(); // 999 執行完畢,f2的內存空間被銷毀。 f1的內存空間也被銷毀,nAdd雖然是全局變量,但其是方法的屬性,自然也被銷毀。
nAdd(); // undefined
f1()(); // 還是999
由上面我們可以提出幾點疑問:
1.注意變量的訪問范圍和生命周期
2.方法內部的全局變量會隨著方法的銷毀而銷毀。 注意變量的訪問范圍和生命周期!
3.第二種調用方式:立即執行函數。
一句話總結:
1.閉包就是能夠讀取其他函數內部變量的函數(是其他函數的內部函數)。
2.定義在一個函數內部的函數"。
3.閉包就是將函數內部和函數外部連接起來的一座橋梁。
4.由于js其特殊的作用域規則,要通過外部來訪問函數的內部變量。 ——————閉包就是干這個的!
補充
代碼理解:
function f1(){
var n=999;
nAdd=function(){n+=1;return n;} // 全局變量:都可以調用,前提是創建了-----銷毀之前外部可以訪問。
function f2(){
alert(n);
}
return f2;
}
alert(f1()); // 調用f1,返回f2 不調用f1都不會創建nAdd
alert(nAdd());