JavaScript Function Closure (閉包)
Closure (中文稱做閉包) 是一個屬於函數特殊的執行環境 (scope; context),這「封閉」的環境中保存 (record) 了讓函數可以持續 (甚至在 function 被 return 後) 存取的獨立自由變數 (free variable),換句話說,closure 是讓函數能「記得」被建立時的環境的一種機制。
那怎麼建立一個 closure?很簡單,從一個 function return 另一個 nested function 就可以建立一個 closure 環境。
例如:
function makeFunc() {
// 一個局部變數
var name = 'Fooish';
function displayName() {
// 內部函數可以存取外部函數的變數
alert(name);
}
// 返回一個內部函數,並創建一個 closure
return displayName;
}
var myFunc = makeFunc();
// 顯示 Fooish
myFunc();
上面例子中,makeFunc() 執行時返回一個 function,同時自動創建了一個 closure 環境。closure 像是一個特殊的物件 (指定給了 myFunc),closure 中包含一個函數 (displayName),以及函數 (makeFunc) 執行當時的環境,讓你在函數返回後還是可以持續存取 closure 保存的環境 (像是能存取 name 變數,name 變數不會因為函數返回後而被刪除)。
而每一個 closure 中保存的都是一個獨立的環境。
再舉一個 closure 的例子:
function makeAdder(x) {
return function(y) {
// 函數被 return 後,還是能繼續存取環境中的 x 變數
return x + y;
};
}
// 建立一個 closure
var add5 = makeAdder(5);
// 建立另一個 closure
var add10 = makeAdder(10);
// 顯示 7
alert(add5(2));
// 顯示 12
// 兩個 closure 的環境是獨立的
alert(add10(2));
其實不僅是 return function 才能建立一個 closure,你也可以返回任何 object,只要這 object 會持續存取內部環境的變數。
舉個利用 IIFE 和 closure 實作私有方法 (private method) 的例子:
var counter = (function() {
// 私有變數
var privateCounter = 0;
// 私有方法
function changeBy(val) {
// 存取 closure 環境中的變數
privateCounter += val;
}
// 返回一個 object,並建立一個 closure 環境
return {
increment: function() {
// 存取 closure 環境中的函數
changeBy(1);
},
decrement: function() {
// 存取 closure 環境中的函數
changeBy(-1);
},
value: function() {
// 存取 closure 環境中的變數
return privateCounter;
}
};
}());
// 顯示 0
alert(counter.value());
counter.increment();
counter.increment();
// 顯示 2
alert(counter.value());
counter.decrement();
// 顯示 1
alert(counter.value());