先解釋一下什麼是閉包
閉包就是內建函式通過某種方式使其可見範圍超出了其定義的範圍,這就產生了一個在其定義範圍內的閉包.
我們先來瞭解一下內建函式(inner function)
javascript是支援內建函式申明(inner function declaration)的程式設計語言,
內建函式就是在另一個函數的內部定義,比如
function outerFun(){
function innerFun(){
alert('hello');
}
}
函數innerFun就是內建函式, 它在函數outerFun範圍內是可見的,
也就是說innerFun函數的命名空間(namespace)是在outerFun範圍之內.
正確調用
function outerFun(){
function innerFun(){
alert('hello');
}
innerFun();
}
outerFun(); alerts hello
錯誤調用(error)
function outerFun(){
function innerFun(){
alert('hello');
}
}
innerFun();
那麼如果我想在函數outerFun外面調用函數innerFun,我該如何做呢
做法1
var globVar;
function outerFun() {
function innerFun() {
alert('hello');
}
globVar = innerFun;
}
outerFun();
globVar();
做法2
function outerFun() {
function innerFun() {
alert('hello');
}
return innerFun ;
}
var globVar = outerFun();
globVar();
做法3
function outerFun() {
function innerFun() {
alert('hello');
}
return {'innerFun'innerFun} ;
}
var globVar = outerFun();
globVar.innerFun();
以上三種做法把內建函式的可見範圍擴大了, 其中最後一種做法是把內建函式當做匿名對象{'innerFun'innerFun}的屬性,並隨之一起返回.
從中看到在javascript裡面,函數名稱可以當作是一種引用變數,類似於c裡面指標的概念,在這裡,隨著程式的執行
會產生兩個引用變數指向內建函式innerFun,一個是globVar(第三種做法是globVar.innerFun),另一個是其函數自身innerFun,
只不過這兩個變數的可見範圍不一樣,即命名空間不一樣.
javascript記憶體回收行程會在函數最後一個引用變數被廢棄後,釋放其所佔用的記憶體.
再瞭解一下變數範圍
例1 內建函式變數
在內建函式內申明的變數其可見範圍就在其函數內
function outerFun() {
function innerFun() {
var innerVar = 0;
innerVar++;
alert(innerVar);
}
return innerFun;
}
var globVar = outerFun();
globVar(); Alerts 1
globVar(); Alerts 1
var innerVar2 = outerFun();
innerVar2(); Alerts 1
innerVar2(); Alerts 1
每一次內建函式調用,一個新的innerVar變數都被建立,所以結果顯示都是1
例2 內建函式引用全域變數(global variables)
var globVar = 0;
function outerFun() {
function innerFun() {
globVar++;
alert(globVar);
}
return innerFun;
}
var globVar = outerFun();
globVar(); Alerts 1
globVar(); Alerts 2
var globVar2 = outerFun();
globVar2(); Alerts 3
globVar2(); Alerts 4
每一次內建函式的調用,全域變數都增加1,所以顯示結果都是依次遞增.
例3 內建函式引用外部函數變數
function outerFun() {
var outerVar = 0;
function innerFun() {
outerVar++;
alert(outerVar);
}
return innerFun;
}
var globVar = outerFun();
globVar(); Alerts 1
globVar(); Alerts 2
var globVar2 = outerFun();
globVar2(); Alerts 1
globVar2(); Alerts 2
注意在第2次調用outerFun()的時候重新建立了一個新的變數outerVar,所以顯示結果是1,2,1,2
什麼是閉包(closures)呢, 就是內建函式通過某種方式使其可見範圍超出了其定義的範圍, 如上例3,globVar 就是函數outerFun()的一個閉包,
而閉包產生的時機就是這句代碼var globVar = outerFun(); 再看上例3,閉包globVar第一次調用之後,變數outerVar 值 1 還是在記憶體
中,沒有回收,因為閉包globVar第二次調用的時候其值已經遞增為2 ,只要globVar沒有被廢棄掉,則outerVar的值就會一直存在. 像outerVar
這樣的變數稱其為自由變數
看完這些我們再瞭解一下閉包與物件導向編程之間的聯絡
看看下面的例子
function outerFun() {
var outerVar = 0;
function innerFun() {
outerVar++;
alert(outerVar);
}
function innerFun2() {
outerVar = outerVar + 2;
alert(globVar);
}
return {'innerFun' innerFun, 'outerFun2' outerFun2};
}
var globVar = outerFun();
globVar.innerFun(); Alerts 1
globVar.innerFun2(); Alerts 3
globVar.innerFun(); Alerts 4
var globVar2 = outerFun();
globVar2.innerFun(); Alerts 1
globVar2.innerFun2(); Alerts 3
globVar2.innerFun(); Alerts 4
outerFun()可以看成是類,globVar,globVar2可以看成是兩個執行個體,執行個體變數就是outerVar,並且是private. 函數innerFun(),
innerFun2()就是執行個體方法.
可能這還不是很清楚,在看下面的例子
function Boy(){
var name;
function setName(vName){
name = vName;
}
function getName(){
return name;
}
return {'setName' setName, 'getName' getName};
}
var boy1 = Boy();
boy1.setName(zhuzhenhua);
alert(boy1.getName());
作者:zmyxmjz