天天看點

JS程式設計建議——61:使用閉包跨域開發

建議61:使用閉包跨域開發

閉包是指詞法表示包括不必計算的變量的函數,閉包函數能夠使用函數外定義的變量。閉包結構有以下兩個比較鮮明的特性。

(1)封閉性

外界無法通路閉包内部的資料,如果在閉包内聲明變量,外界是無法通路的,除非閉包主動向外界提供通路接口。

(2)持久性

對于一般函數來說,在調用完畢之後,系統會自動登出函數,而對于閉包來說,在外部函數被調用之後,閉包結構依然儲存在系統中,閉包中的資料依然存在,進而實作對資料的持久使用。例如:

function f( x ){

}

var c = f( 1 );

alert(c()); //1。調用閉包函數

在上面示例中,首先在函數f結構體内定義兩個變量,分别存儲參數和閉包結構,而閉包結構中寄存着參數值。當調用函數f之後,函數結構被登出,它的局部變量也随之被登出,是以變量a中存儲的參數值也随之丢失。但由于變量b存儲着閉包結構,是以閉包結構内部的參數值并沒有被釋放,在調用函數之後,依然能夠從閉包結構中讀取到參數值。

從結構上分析,閉包函數與普通函數沒有什麼不同,主要包含以下類型的辨別符:

函數參數(形參變量)。

arguments屬性。

局部變量。

内部函數名。

this(指代閉包函數自身)。

其中this和arguments是系統預設的函數辨別符,不需要特别聲明。這些辨別符在閉包體内的優先級是(其中左側優先級大于右側):this → 局部變量 → 形參 → arguments → 函數名。

下面以一個經典的閉包示例來示範上述抽象描述:

1 function f(x){ // 外部函數

2 var a = x; // 外部函數的局部變量,并把參數值傳遞給它

3 var b = function(){ // 内部函數

4 return a; // 通路外部函數中的局部變量

5 };

6 a++; // 通路後,動态更新外部函數的變量

7 return b; // 内部函數

8 }

9 var c = f(5); // 調用外部函數,并指派

10 alert(c()); // 調用内部函數,傳回外部函數更新後的值6

示範步驟說明如下:

第1步,程式預編譯之後,從第9行開始解析執行,建立上下文環境,建立調用對象,把參數、局部變量、内部的函數轉換為對象屬性。

第2步,執行函數體内代碼。在第6行執行局部變量a的遞加運算,并把這個值傳遞給對象屬性a,内部函數動态保持與局部變量a的聯系,同時更新自己内部調用變量的值。

第3步,外部函數把内部函數傳回給全局變量c,實作内部函數的定義,此時c完全繼承了内部函數的所有結構和資料。

第4步,外部函數傳回後(即傳回值後調用完畢)會自動銷毀,内部的結構、辨別符和資料也随之丢失。

第5步,執行第10行代碼指令,調用内部函數,此時傳回的是外部函數傳回時(銷毀之前)儲存的變量a所存儲的最新資料值,即傳回6。

如果沒有閉包函數的作用,那麼這種資料寄存和傳遞就無法得以實施。例如:

1 function f(x){

2 var a = x;

3 var b = a; // 直接把局部變量的值傳遞給局部變量b

4 a++

5 return b; //局部變量b

6 }

7 var c = f(5);

8 alert(c); //值為5

通過上面的示例可以很直覺地看到,在沒有閉包函數的輔助下,第8行代碼執行後傳回值并沒有與外部函數的局部變量a最後更新的值保持一緻。

閉包在程式開發中具有重要的價值。例如,使用閉包結構能夠跟蹤動态環境中資料的實時變化,并即時存儲。

function f(){

var c = f();

alert(c()); //傳回2,而不是1

在上面示例中,閉包中的變量a存儲的值并不是對上面行變量a的值的簡單複制,而是繼續引用外部函數定義的局部變量a中的值,直到外部函數f調用傳回。閉包不會因為外部函數環境的登出而消失,會始終存在。例如:

按鈕1:(f( ))()

按鈕2:(b = function(){alert( a );})()

按鈕3:(c = function(){a ++ ;})()

按鈕4:(d = function( x ){a = x; }) (100)

在上面示例中,在函數f中定義了3個閉包函數,它們分别指向并寄存局部變量a的值,并根據不同的操作動态跟蹤變量a的值。當在浏覽器中預覽時,首先應該單擊“按鈕1”,調用函數f,生成3個閉包,3個閉包同時指向局部變量a的引用,是以,當函數f傳回時,這3個閉包函數都沒有被登出,變量a由于被閉包引用而繼續存在。這時,如果直接單擊“按鈕2”和“按鈕4”,那麼會由于沒有在系統中生成閉包結構,而彈出編譯錯誤。單擊“按鈕3”将動态遞增變量a的值,此時如果單擊“按鈕2”,則會彈出提示值2。如果單擊“按鈕4”,則向變量a傳遞值100,将動态改變閉包中寄存的值,此時如果單擊“按鈕2”,則會彈出提示值100。

繼續閱讀