![]() |
VOOZH | about |
javaScript是一種弱類型、動態的、基於原型的語言,這種語言特性使得它非常容易、
甚至是普通的方式實現其中的一些模式。
單體模式的思想在於保證一個特定類僅有一個實例。這就意味著當您第二次使用同一個
類創建新對象的時候,應該得到與第一次所創建對象完全相同對象。
在javaScript中沒有類,只有對象。當您創建一個新對象時,實際上沒有其他對象與其
類似,因此新對象已經是單體了。使用對象字面量創建一個簡單的對象也是一個單體的
例子。
var obj ={
myprop:’my value』
};
在javaScript中,對象之間永遠不會完全相等,除非他們是同一個對象,因此即使創建
一個具有完全相同成員的同類對象,它也不會與第一個對象完全相同。
var obj2 = {
myprop:’mu value』
};
obj === obj2 //false
obj == obj2 //false
因此,可以認為每次在使用對象字面量創建對象的時候,實際上就正在創建一個單體,
並且並不涉及任何特殊語法。
javaScript中並沒有類,因此對單體咬文嚼字的定義嚴格說來並沒有意義。但是
javaScript中具有new語法可使用構造函數來創建對象,而且有時可能需要使用這種語法
的單體實現。這種思想在於當使用一個構造函數以new操作符來創建多個對象時,應該僅
獲得指向完全相同的對象的新指針。
下面的代碼顯示了其預期行為
var uni = new Universe;
在上面的例子中,uni對象僅在第一次調用構造函數時被創建。在第二次及以後的創建時
將會返回同一個uni對象。這就是為什麼uni===uni2,因為它們本質上是指向同一個對象
的兩個引用。那麼如何在javaScript中實現這種模式呢?
需要Universe構造函數緩存該對象實例this,以便當第二次調用該構造函數時能夠創建並
返回同一個對象。有多種選擇可以實現這一目標:
1.可以使用全局變量來存儲該實例,但是並不推薦使用這種方法,因為在一般原則下,
全局變量有部分缺點。此外,任何人都能覆蓋該全局變量。
也可以有屬性。可以使用類似Universe.instance的屬性並將實例緩存在該屬性重工,這
是一種很好的實現方法,這種解決方案唯一的缺點在於instance屬性是公開可訪問的屬
性,在外部代碼中可能會修改該屬性,以至於會丟失了該實例。
如例子:
function Universe{
//判斷是否有實例
if(typeof Universe.instance === 『object』){
return Universe.instance;
}
//正常進行
this.start_time = 0;
this.bang = 「Big」;
//緩存
Universe.instance = this;
}
//
var uni = new Universe;
var uni2 = new Universe;
uni === uni2; //true
這種方法是一個非常直接的解決方法,其唯一的缺點在於其instance屬性是公開的,雖
然其他代碼不太可能會無意中修改該屬性,但是仍然存在這種可能性。
3.可以將該實例包裝在閉包中。這樣可以保證該實例的私有屬性並且保證該實例不會被
構造函數之外的代碼所修改,缺點就是帶來了額外的閉包開銷。
//正常進行
this.start_time=0;
this.bang = 「big」;
//重寫該構造函數
Universe = function{
return instance;
};
}
var uni = new Universe;
var uni2 = new Universe;
uni === uni2; //true
當第一次調用原始構造函數時,它像往常一樣返回this,然後,在第二次、第三次調用
時,將執行重寫構造函數。該重寫構造函數通過閉包訪問了私有instance 變量,並且僅
簡單返回了該instance.在重寫構造函數會丟失所有在初始定義和重定義時刻之間添加到
它裡面的屬性。在這列的特定情況下,任何添加到universe的原型中對象都不會存在指
向由原始實現所創建實例的活動連結。
創建一個對象,並且似的私有instance指向該對象,從第二次調用之後,該構造函數僅
返回該私有變量,通過這個新的實現方式,前面所有代碼片段的測試也都會按照預期運
行。
var Universe;
(function {
var instance;
Universe = function Unvierse{
if(instance){
return instance;
}
instance = this;
//所有功能
this.start_time = 0;
this.bang = 「Big」;
};
});