讀古今文學網 > 編寫高質量代碼:改善JavaScript程序的188個建議 > 建議105:比較單例的兩種模式 >

建議105:比較單例的兩種模式

在JavaScript中,單例模式(即實例結構模式)是最基本、最有用的模式之一。這種模式提供了一種將代碼組織為一個邏輯單元的手段,這個邏輯單元中的代碼可以通過單一的變量進行訪問。確保單例對像只有一份實例,就可以確信自己的所有代碼使用的都是同樣的全局資源。單例類在JavaScript中用途廣泛:

❑可以用來劃分命名空間,以減少全局變量的數量。

❑可以在一種名為分支的技術中用來封裝瀏覽器之間的差異。

❑可以借助於單例模式,將代碼組織得更為一致,從而使代碼更容易閱讀和維護。

1.第一種模式:對像直接量

最基本的單例實際上是一個對像字面量,它將一批有一定關聯的方法和屬性組織在一起。


var Singleton={

attribute1:true;

attribute2:10

method1:function{},

method2:function{}

};


這些成員可以通過Singleton加圓點運算符來訪問,例如:


Singleton.attribute1=false;

var total=Singleton.attribute2+5;

var result=Singleton.method1;


對像字面量只是用於創建單例的方法之一,並非所有對象字面值都是單體,如果它只是用來模仿關聯數組或容納數據的話,那顯然不是單例。但如果它用來組織一批相關方法和屬性,那就可能是單例,其區別主要在於設計者的意圖。

在單例對像內創建類的私有成員的最簡單、最直接的方法是使用下畫線表示法。在JavaScript業界,如果變量和方法使用下畫線,則表示該變量和方法是私有方法,只允許內部調用,第三方不應該去調用。


GiantCorp.DataParser={

//私有方法

_stripWhitespace:function(str){

return str.replace(/\s+/,'');

},

//公用方法

stringToArray:function(str,delimiter,stripWS){

if(stripWS){

str=this._stripWhitespace(str);

}

var outputArray=this._stringSplit(str,delimiter);

return outputArray;

}

};


在stringToArray方法中使用this訪問單體中的其他方法,這是訪問單體中其他成員或方法最簡便的方式。這樣做有一點風險,因為this並不一定指向GiantCorp.DataParser。例如,如果把某個方法用做事件監聽器,那麼其中的this指向的是window對象,因此大多數JavaScript庫都會為事件關聯進行作用域校正,如在這裡使用GiantCorp.DataParser比使用this更為安全。

2.第二種模式:使用閉包

在單例對像中創建私有成員的第二種方法是借助閉包。因為單例只會被實例化一次,所以不必擔心自己在構造函數中聲明了多少成員。由於每個方法和屬性都只會被創建一次,所以可以把它們聲明在構造函數內部。使用閉包創建擁有私有成員的單例類的示例如下:


MyNamespace.Singleton=(function{

//私有成員

var privateAttribute1=false;

function privateMethod1{}

return{

//公有成員

publicAttribute1:true;

publicMethod1:function{},

};

});


這種單例模式又稱為模塊模式,指的是它可以把一批相關方法和屬性組織為模塊並起到劃分命名空間的作用。將私有成員放在閉包中可以確保其不會在單例對像之外被使用,因此開發人員可以自由地改變對象的實現細節,而不會殃及別人的代碼。還可以使用這種辦法對數據進行保護和封裝。

在JavaScript中,使用單例模式的主要優點如下:

❑對代碼的組織作用。單例模式將相關方法和屬性組織在一個不會被多次實例化的單例中,可以使代碼的調試和維護變得更輕鬆。描述性的命名空間還可以增強代碼的自我說明性。將方法包裹在單例中,可以防止它們被其他程序員誤改。

❑單例模式的一些高級變體可以在開發週期的後期用於對腳本進行優化。

在JavaScript中,使用單例模式的主要缺點如下:

❑因為提供的是一種單點訪問,所以它有可能導致模塊間的強耦合。單體最好是留給定義命名空間和實現分支型方法使用,在這些情況下耦合不是什麼問題。

❑有某些更高級的模式會更符合任務的需要。虛擬代理能給予開發人員對實例化方式更多的控制權。也可以用一個真正的對象工廠來取代分支型單例。