天天看點

JS程式設計建議——69:使用子產品化規避缺陷

建議69:使用子產品化規避缺陷

使用函數和閉包可以構模組化塊。所謂子產品,就是一個提供接口卻隐藏狀态與實作的函數或對象。通過使用函數構模組化塊,可以完全摒棄全局變量的使用,進而規避JavaScript語言缺陷。全局變量是JavaScript最為糟糕的特性之一,在一個大中型Web應用中,全局變量可能會帶來不可預料的後果。

例如,要為String擴充一個deentityify方法,其設計任務是尋找字元串中的HTML字元實體并将其替換為對應的字元。在一個對象中儲存字元實體的名字及與之對應的字元是有意義的。

可以把deentityify放到一個全局變量中,但全局變量存在很多潛在危害。可以把deentityify定義在該函數本身中,但會帶來運作時的損耗,因為在該函數每次被執行時,這個方法都會被求值一次。理想的方式是将deentityify放入一個閉包,而且也許還能提供一個增加更多字元實體的擴充方法。

String.method('deentityify', function() {

}());

在上面代碼中,為String類型擴充了一個deentityify方法,它調用字元串的replace方法來查找以“&”開頭和以“;”結束的子字元串。如果這些字元可以在字元實體表entity中找到,那麼就将該字元實體替換為映射表中的值。deentityify方法用到了一個正規表達式:

});

在最後一行使用()運算符立刻調用剛剛構造出來的函數。這個調用所建立并傳回的函數才是deentityify方法。

document.writeln('<">'.deentityify()); // <">

子產品利用了函數作用域和閉包來建立綁定對象與私有成員的關聯。在這個示例中,隻有deentityify方法才有權通路字元實體表entity這個資料對象。子產品開發的一般形式是:一個定義了私有變量和函數的函數,利用閉包建立可以通路到的私有變量和函數的特權函數,最後傳回這個特權函數,或者把它們儲存到可通路的地方。

使用子產品可以避免全局變量的濫用,進而保護資訊的安全性,實作優秀的設計實踐。使用這種模式也可以實作應用程式的封裝,或者建構其他執行個體對象。

子產品模式通常結合執行個體模式使用。JavaScript的執行個體就是用對象字面量表示法建立的,對象的屬性值可以是數值或函數,并且屬性值在該對象的生命周期中不會發生變化。子產品通常作為工具為程式其他部分提供功能支援。通過這種方式能夠建構比較安全的對象。

下面代碼構造一個用來産生序列号的對象。serial_maker()函數将傳回一個用來産生唯一字元串的對象,這個字元串由兩部分組成:字元字首+序列号。這兩部分可以分别使用set_prefix和set_seq方法進行設定,然後調用執行個體對象的gensym方法讀取這個字元串。當執行該方法時,都會自動産生唯一一個字元串。

var serial_maker = function() {

};

var seqer = serial_maker();

seqer.set_prefix('Q');

seqer.set_seq(1000);

var unique = seqer.gensym(); //"Q1000"

var unique = seqer.gensym(); //"Q1001"

seqer包含的方法都沒有用到this或that,是以沒有辦法“損害”seger,除非調用對應的方法,否則無法改變prefix或seq的值。由于seqer對象是可變的,是以它的方法可能會被替換掉,但替換後的方法依然不能通路私有成員。seqer就是一組函數的集合,而且這些函數被授予特權,擁有使用或修改私有狀态的能力。如果把seqer.gensym作為一個值傳遞給第三方函數,這個函數就能通過它産生唯一字元串,卻不能通過它來改變prefix或seq的值。

繼續閱讀