單件是JavaScript中最基本、最有用的設計模式,而你今後也會經常的使用這個模式。通過單件,我們可以把統一到一個邏輯單元中并且提供一個唯一的入口,這就保證你所有的引用都是用的這個全局資源。
單件的用途有:一、提供一個Namespacing、二、提供一種被稱為branching的技術。
單件的基本形式:
/* Basic Singleton Pattern */
var
Map
=
{
name:"Map G",
createdate:"2008-09-19",
sayMyName:function(){
alert("My Name is "
+
this.name);
},
tellMeWords:function(arg){
alert("What you told to me is "
arg
"\n I won't tell anyone!")
}
}
命名空間:
我們可以給單件提供新的屬性,并且能夠建立獨立的命名空間,而避免我們寫的屬性或者程式被無意的覆寫。我們接着單件的基本形式中的例子可以建立新的屬性:
Map.Property
createdata:"2000-09-09",
width:"100",
height:"200"
Map.Utility
getSize:function(x,y){
return
x*y;
這樣,同樣的createdate屬性即便一樣,也不會造成程式中的沖突了。
在單件中添加私有成員:
利用下劃線。最簡單、最直接的聲明私有變量的方式就是使用下劃線。這樣就可以使其他程式員明白,這些變量是私有的、隻是在對象内部使用,同時也可以使其他程式員避免直接通路他們。
_isMature:function(){
alert("Of Course, I'm Mature!");
使用Closure。
使用Closure,我們可以實作私有變量和共有變量。因為singleton在調用過程中隻會有一個執行個體,是以我們就不必擔心私有成員耗費資源的問題了。例子如下:
MyNamespace
{};
MyNamespace.Singleton
(function(){
var
privateAttribute1
"Name";
privateAttribute2
true;
function
privateMethod1(){
return
publicAttribute1:"Public",
publicAttribute2:"false",
publicMethod1:function(){
}
};
})();
Lazy Instantiation
以上所讨論的各種各樣的單件實作,他們都有一個共同點,那就是當代碼加載時就立即建立的。如果你有一個需要複雜配置的單件、或者他加載的時候需要占用大量資源,也許我們就該考慮延時實作他了。Lazy Loading就是用來解決這個問題的,常被用在需要加載大量資料的時候。
Lazy Loading singletons與之前的singleton不同,你不能通過MyNamespace.methdName()來進行通路,而必須通過Mynamespace.getInstance().methodName()來通路。GetInstance方法首先檢查單件是否進行執行個體化,如果沒有,則建立并傳回,下面是例子:
//Lazy instantiation
Car
Car.MyPorsche
uniqueInstance;
CarOfPorsche(){
var
name
"My Favorate Porsche";
buydate
"2008-09-22";
speed:"120Kmp",
getName:function(){
return
name;
}
};
getInstance:function(){
if(!uniqueInstance){
uniqueInstance
CarOfPorsche();
return
//Normal Singleton
Car.MyBenz
"My Benz Car";
"2009-10-10";
speed:"140Kmp",
getName:function(){
Lazy loading的一個缺點是增加了代碼的複雜性,而且代碼開始變得難以了解。在調用的時候,我們需要通過Car.MyPorsche.getInstance().speed來調用,這就增加了代碼的複雜行。當然,我們可以通過
var
porsche
Car.MyPorsche.getInstance();
alert(porsche.getName()
"'s speed is "
porsche.speed);
來簡化調用。
分支(Branching):
分支是一項将不同浏覽器的差別封裝到動态方法中的技術。我們以建立XHR對象為例。對于大多數浏覽器,XHR 是XMLHttpRequest對象的一個執行個體,或者是較早版本的IE的不同ActiveX的一個執行個體。這個方法總是伴随着對于浏覽器的檢測,如果我們沒用用Branching這項技術,沒次我們都需要運作浏覽器檢測的方法來檢查,這降低了代碼的效率。
一個更加高效的方式就是當代碼加載時,根據浏覽器的不同賦予一個固定的值,在不同的浏覽器下,我們隻執行這個實作的擴充。在運作時刻動态改變一個Function的内容,這正是JavaScript靈活的強大的所在。
那麼分支如何應用在單件中呢,看下面的例子:
//Branching
//SimpleXhrFactory Singleton
SimpleXhrFactory
standard
createObject:function(){
new
XMLHttpRequest();
activexNew
ActiveXObject("Msxml2.XMLHTTP");
activexOld
ActiveXObject("Microsoft.XMLHTTP");
testObject;
try{
testObject
standard.createObject();
standard;
}catch(e){
try{
testObject
activexNew.createObject();
activexNew;
}catch(e){
try{
testObject
activexOld.createObject();
activexOld;
}catch(e){
throw
Error("No XMLHTTP Object found in this environment!");
什麼時候使用單件:
當需要使用命名空間或者子產品化你的代碼的時候,應該盡量的使用單件。單件是JavaScript中使用最廣泛的一個設計模式,無論在什麼規模的項目中,你都能看到他的影子。
使用單件的好處:
單件的主要作用是提供了一個格式化你的代碼的方法。通過吧相似的方法和屬性集合到一個單間中,并且隻能被執行個體化一次,你就可以更友善的調試代碼。