閉包的概念: 在電腦科學中,閉包(也稱詞法閉包或函數閉包)是指一個函數或函數的引用,與一個引用環境綁定在一起。這個引用環境是一個存儲該函數每一個非局部變數(也叫自由變數的表)。已暈^^ 閉包,不同於一般的函數,它允許一個函數在立即詞法作用域外調用時,仍然訪問非本地變數 ——from維基百科 閉包其
閉包的概念:
在電腦科學中,閉包(也稱詞法閉包或函數閉包)是指一個函數或函數的引用,與一個引用環境綁定在一起。這個引用環境是一個存儲該函數每一個非局部變數(也叫自由變數的表)。已暈^^
閉包,不同於一般的函數,它允許一個函數在立即詞法作用域外調用時,仍然訪問非本地變數 ——from維基百科
閉包其實就是能夠讀取其他函數內部變數的函數。
由於在javascript語言中,只由函數內部的子函數才能讀取局部變數,因此可以把閉包簡單理解成“定義在一個函數內部的函數”
所以,在本質上,閉包就是將函數內部和函數外部鏈接起來的一座橋梁
——form阮一峰
理解閉包需要先瞭解一下“變數作用域”和“如何讀取局部變數”的概念:
一、變數的作用域:
變數的作用域無非就是兩種:全局變數和局部變數
javascript語言的特殊之處,就在於函數內部可以直接讀取全局變數。
var scope = "local scope"; function outer(){ console.log(scope); } outer(); //local scope
另一方面,在函數外部自然無法讀取函數內的局部變數:
function outer(){ var scope = "local scope"; }
outer(); console.log(scope);
大家想下,上述的結果會是腫麽樣呢?
答案當然是大家所想的error了: scope is not defined
還有一個需要註意的地方,函數內部聲明變數的時候,一定要使用var關鍵字,如果不用的話,那麼你實際上是聲明瞭一個全局變數
function outer(){ scope = "local scope"; } outer(); console.log(scope);
???這個的答案是啥呢? local scope 所以要記得使用var關鍵字額
二、如何從外部讀取局部變數?
讀取局部變數?剛剛不是說無法讀取到函數內的局部變數me?暈了^^
其實是醬紫的,通常情況下是無法讀取到函數內部的局部變數的,不過通過變通方法就可以實現鳥!
那就是在函數的內部,再定義一個函數。
function outer(){ var scope = "local scope"; function inner(){
console.log(scope);//local scope
} }
在上面的代碼中,函數inner被包含在函數outer內部,這時outer內部的所有變數,對inner都是可見的。但是反過來就不行了,inner內部的局部變數,對outer是不可見的。這就是javascript語言特有的“鏈式作用域”結構(chain scope),子對象會一級一級地向上尋找所有父對象的變數。所以,父對象的所有變數,對子對象都是可見的,反之則不成立。
既能inner可以讀取outer中的局部變數,那麼只要把inner作為返回值,我們就可以在outer外部讀取它的內部變數了嗎!
function outer(){ var scope = "local scope"; function inner(){ console.log(scope) } return inner; } var func = outer(); func();
這次的結果會是 scope is not defined 嗎?
大家去驗證下吧。
其實答案是這樣子的 local scope
上述代碼中inner函數,就是閉包
閉包的用途
閉包可以用在很多地方。它的最大用處有兩個,一個是前面提到的可以讀取函數內部的局部變數,另一個就是讓這些變數始終保持在記憶體中。
function outer(){ var n = 999; nAdd = function(){n+=1}; function inner(){ alert(n); } return inner; } var result = outer(); result(); //999 nAdd(); result(); //1000
在這段代碼中,result實際上就是閉包inner函數,它一共運行了兩次,第一次的值是999,第二次的值是1000,這證明瞭,函數outer中的局部變數n一直保存在記憶體中,並沒有在inner調用後自動清除。
使用閉包的註意點
閉包靈活和方便,
閉包也存在“空間浪費”,“記憶體泄漏”,“性能消耗”的問題,所以不能濫用閉包。