JavaScript中實現單體模式分享,javascript單體

來源:互聯網
上載者:User

JavaScript中實現單體模式分享,javascript單體

單體模式作為一種軟體開發模式在眾多物件導向語言中得到了廣泛的使用,在javascript中,單體模式也是使用非常廣泛的,但是由於javascript語言擁有其獨特的物件導向方式,導致其和一些傳統物件導向語言雖然在單體模式的思想上是一致的,但是實現起來還是有差異的。

首先來看看傳統物件導向語言對於單體模式的定義:單體模式是只能被執行個體化一次並且可以通過一個眾所周知的訪問點來訪問的類。這個定義有兩點突出了傳統物件導向語言的特徵,即類和執行個體化,所以對於傳統物件導向語言來講,單體模式是建立在其類和執行個體化的自然特性之上的,即使用關鍵字class定義一個類,該類可通過new關鍵字來執行個體化,但是需要保證每次被new執行個體化之後得到的都是同一個執行個體或者說只能通過new來調用其建構函式一次。

再來看看javascript中對於單體模式的定義:單體是一個用來劃分命名空間並將一批相關方法和屬性群組織在一起的對象,如果它能夠被執行個體化,那麼只能被執行個體化一次。對比上面的定義,你會發現這裡的單體定義將其實質定義為對象,而不是傳統物件導向語言中的類,這也表明了javascript這門語言是基於對象的。同時後面又指出,如果能夠被執行個體化,這說明了在javascript中單體定義應該有好幾種方式,存在一種或幾種能夠被執行個體化即使用new關鍵字來建立單體對象的方式,但是這種方式不是javascript自身的自然特徵,因為使用new關鍵字創造出來的對象,實際上都是通過function來類比定義其建構函式的(雖然ES6開始支援class關鍵字了,但是目前還沒有得到瀏覽器廣泛支援),那麼如何使用javascript的自然特徵來實現單體模式呢?

var Singleton={  attribute1:true,  attribute2:10,  method1:function(){  },  method2:function(arg){  }}

這裡定義了一個對象Singleton,內部包含若干屬性和方法,將其包含在頁面中,js載入的時候就建立了這個對象,在調用時使用Singleton.method1來調用,它的執行個體化是隨著頁面載入js解析執行過程中完成的,我們並沒有使用new關鍵字來執行個體化這個對象,這也是javascript中實現單體模式和傳統物件導向語言一個很大的不同。這種方式更為簡單易於理解。但是這種方式存在若干缺點,一個很明顯的缺點是它並沒有提供命名空間,其他程式員如果在頁面中也定義了一個Singleton變數,那麼很容易改寫和混淆這個單體對象,於是針對這個問題,將其改寫如下:

var mySpace={};mySpace.Singleton={  attribute1:true,  attribute2:10,  method1:function(){  },  method2:function(arg){  }}


這裡首先定義了一個mySpace的命名空間,然後將單體對象Singleton掛載在這個對象的下面,這大大減少了和其他程式員衝突以及誤操作的可能,即使其他人在全域範圍中定義一個Singleton變數,也不會汙染到這個單體對象,這就實現了前面定義中所說的劃分命名空間並且將一些相關屬性和方法組織在一起的功能。

這個方法依然存在缺點,這個單體對象的所有屬性和方法都是共有的,外部可隨時訪問和修改,於是採用閉包來類比私人屬性和方法,如下:

mySpace.Singleton=(function(){  var privateAttribute1=false;  var privateAttribute1=[1,2,3];  function privateMethod1(){  }  function privateMethod2(){  }  return {  publicAttribute1:true,  publicAttribute2:10,  publicMethod1:function(){    privateAttribute1=true;    privateMethod1();  },  publicMethod2:function(arg){    privateAttribute1=[4,5,6];    privateMethod2();  }  }})();


在這裡我們直接給該單體對象賦值了一個匿名自執行的函數,在該函數中使用var和function關鍵字分別來定義其私人屬性和方法,這些在函數外部(單體對象外部)是無法直接存取的,因為函數一執行完畢,其內部範圍的空間就會被回收,這也就是能夠利用閉包來類比私人屬性和方法的原因所在。在該函數(閉包)中,同時最終返回一個對象,這個對象中包含一些公有方法和屬性,在外部可以直接調用,同時這些公有方法由於定義在函數內部,所以可以調用其私人屬性和方法,但是外界只能通過返回的公有方法和屬性來完成某些操作,不能夠直接調用Singleton.privateMethod1這些屬性。這就使得該單體對象既隔離了外界去直接存取其私人屬性和方法,又提供給外界一些共有屬性和方法去完成某些操作。

這種匿名函數自執行所構造的單體模式在很多js庫中被廣泛使用,但是依然存在一個問題,如果我們在載入頁面的時候並不需要用到該對象,而且該對象的建立比較耗費開銷(如需要進行大量計算或需要多次訪問dom樹及其屬性等)時,合理的做法是需要它的時候再去建立它,而不是隨著js的解析執行直接去建立,這種概念被稱之為惰性載入(lazy loading),於是修改以上代碼如下:

mySpace.Singleton=(function(){    var uniqueInstance;    function constructor(){      var privateAttribute1=false;      var privateAttribute1=[1,2,3];      function privateMethod1(){      }      function privateMethod2(){      }      return {        publicAttribute1:true,        publicAttribute2:10,        publicMethod1:function(){          privateAttribute1=true;          privateMethod1();        },        publicMethod2:function(arg){          privateAttribute1=[4,5,6];          privateMethod2();        }      }    }    return {      getInstance:function(){       if(!uniqueInstance){         uniqueInstance=constructor();       }        return uniqueInstance;      }    }  })();

這裡首先在匿名函數中定義了一個私人變數uniqueInstance,作為一個判斷單體對象是否被建立出來的控制代碼,然後將剛才所有對單體對象定義的屬性和方法都放在一個名為constructor的函數中,只有該函數調用了,才會創造出該單體對象,否則不會直接建立它。然後,返回一個對象,其包含一個getInstance方法,該方法是供外部調用的,調用該方法的時候首先判斷該單體對象是否存在,如果存在就直接返回它,否則調用constructor函數構造這個單體對象再返回它。最後如果我們調用該單體對象的某個方法,需要使用mySpace.Singleton.getInstance().publicMethod1(),這裡,只有我們這樣調用的時候才會建立這個單體對象,否則該單體對象是不會被自動建立的,這實際上就實現了按需載入或者惰性載入。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.