接觸過javascript的人應該聽過閉包(closure),有一種觀點認為是閉包賦予了javascript的強大能力,也賦予了它具備OOP的特征。既然javascript closure如此重要,那麼問題來了,什麼是closure呢?closure有什麼作用?本文将結合我自己對closure的了解,用盡量通俗易懂的方式來進行闡述。
先看看老外對closure怎麼定義的?A closure is an inner function that has access to the outer (enclosing) function's variables—scope chain.從字面上來看,可以翻譯為:閉包就是一個内部函數,它具備通路外部函數變量(這些變量位于作用域鍊中)的能力[注意變量不包含this和arguments]。但這個概念還是過于“專業化”, 不接地氣,隻從概念上來看,非常抽象。下面用一段JS來對應解釋閉包的概念:

個人了解為:fInner函數定義在fOuter的内部,可以通路fOuter定義的變量,這個fInner函數就是closure。closure的 scope chain有3個:一個是fInner函數定義的變量;一個是外部fOuter的變量;還有一個是全局變量(global variables)。closure的作用可以保留變量的值。換句話說,函數fInner就是一個closure。
closure可以幹2件事情:
1)closure可以調用(閉包存儲的外部變量是引用而不是值,這點非常重要)在目前函數以外的定義的變量(即使外部函數已經傳回);
2)closure可以修改外部定義的變量值。
下面通過一段JS代碼來闡述為什麼閉包存儲的外部變量是引用而不是值,這點非常重要!
function mixFunction(a)
{
var result=[],i,n;
n=a.length;
for(i=0;i<n;i++){
result[i]=function(){
//Closure對外部變量是引用
console.log("for i="+i);
return a[i];//a[i-1]
}
}
return result;
}
var mixcall=mixFunction([10,20,30]);
var f=mixcall[0];
console.log(f());//?應該輸出什麼值
f()會輸出 10 麼?答案是undefined!!! ,執行示例如下所示:
為什麼是這樣的呢? 因為閉包對i是引用,在for循環時,會不斷更新i的值。即在調用f()後,i已經被修改為3 (i===3),而a[3]為undefined!! ,示例如下所示:
上述的代碼始終會輸出a[2]的值,也就是30。 那麼問題來了?怎麼解決該問題呢?這就要用到JS中的IIFE技術啦!IIFE技術來解決JS缺少塊級作用域的解決方案。如下代碼所示:
function mixFunctionFix(a)
{
var result=[],i,n;
n=a.length;
for(i=0;i<n;i++){
//IIFE技術來解決JS缺少塊級作用域的解決方案
(function(j){
result[i]=function(){
//Closure對外部變量是引用
console.log("for j="+j);
return a[j];
}
})(i)
}
return result;
}
var mixcall=mixFunctionFix([10,20,30]);
var f=mixcall[0];
console.log(f());//10
控制台執行JS檔案,輸出如下圖所示: