欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JavaScript中實(shí)現(xiàn)單體模式分享

 更新時(shí)間:2015年01月29日 09:20:48   投稿:junjie  
這篇文章主要介紹了JavaScript中實(shí)現(xiàn)單體模式分享,單體模式的定義:單體是一個(gè)用來劃分命名空間并將一批相關(guān)方法和屬性組織在一起的對象,如果它能夠被實(shí)例化,那么只能被實(shí)例化一次,需要的朋友可以參考下

單體模式作為一種軟件開發(fā)模式在眾多面向?qū)ο笳Z言中得到了廣泛的使用,在javascript中,單體模式也是使用非常廣泛的,但是由于javascript語言擁有其獨(dú)特的面向?qū)ο蠓绞?,?dǎo)致其和一些傳統(tǒng)面向?qū)ο笳Z言雖然在單體模式的思想上是一致的,但是實(shí)現(xiàn)起來還是有差異的。

首先來看看傳統(tǒng)面向?qū)ο笳Z言對于單體模式的定義:單體模式是只能被實(shí)例化一次并且可以通過一個(gè)眾所周知的訪問點(diǎn)來訪問的類。這個(gè)定義有兩點(diǎn)突出了傳統(tǒng)面向?qū)ο笳Z言的特征,即類和實(shí)例化,所以對于傳統(tǒng)面向?qū)ο笳Z言來講,單體模式是建立在其類和實(shí)例化的自然特性之上的,即使用關(guān)鍵字class定義一個(gè)類,該類可通過new關(guān)鍵字來實(shí)例化,但是需要保證每次被new實(shí)例化之后得到的都是同一個(gè)實(shí)例或者說只能通過new來調(diào)用其構(gòu)造函數(shù)一次。

再來看看javascript中對于單體模式的定義:單體是一個(gè)用來劃分命名空間并將一批相關(guān)方法和屬性組織在一起的對象,如果它能夠被實(shí)例化,那么只能被實(shí)例化一次。對比上面的定義,你會發(fā)現(xiàn)這里的單體定義將其實(shí)質(zhì)定義為對象,而不是傳統(tǒng)面向?qū)ο笳Z言中的類,這也表明了javascript這門語言是基于對象的。同時(shí)后面又指出,如果能夠被實(shí)例化,這說明了在javascript中單體定義應(yīng)該有好幾種方式,存在一種或幾種能夠被實(shí)例化即使用new關(guān)鍵字來創(chuàng)建單體對象的方式,但是這種方式不是javascript自身的自然特征,因?yàn)槭褂胣ew關(guān)鍵字創(chuàng)造出來的對象,實(shí)際上都是通過function來模擬定義其構(gòu)造函數(shù)的(雖然ES6開始支持class關(guān)鍵字了,但是目前還沒有得到瀏覽器廣泛支持),那么如何使用javascript的自然特征來實(shí)現(xiàn)單體模式呢?

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

  },
  method2:function(arg){

  }
}

這里定義了一個(gè)對象Singleton,內(nèi)部包含若干屬性和方法,將其包含在頁面中,js載入的時(shí)候就創(chuàng)建了這個(gè)對象,在調(diào)用時(shí)使用Singleton.method1來調(diào)用,它的實(shí)例化是隨著頁面載入js解析執(zhí)行過程中完成的,我們并沒有使用new關(guān)鍵字來實(shí)例化這個(gè)對象,這也是javascript中實(shí)現(xiàn)單體模式和傳統(tǒng)面向?qū)ο笳Z言一個(gè)很大的不同。這種方式更為簡單易于理解。但是這種方式存在若干缺點(diǎn),一個(gè)很明顯的缺點(diǎn)是它并沒有提供命名空間,其他程序員如果在頁面中也定義了一個(gè)Singleton變量,那么很容易改寫和混淆這個(gè)單體對象,于是針對這個(gè)問題,將其改寫如下:

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

  },
  method2:function(arg){

  }
}


這里首先定義了一個(gè)mySpace的命名空間,然后將單體對象Singleton掛載在這個(gè)對象的下面,這大大減少了和其他程序員沖突以及誤操作的可能,即使其他人在全局作用域中定義一個(gè)Singleton變量,也不會污染到這個(gè)單體對象,這就實(shí)現(xiàn)了前面定義中所說的劃分命名空間并且將一些相關(guān)屬性和方法組織在一起的功能。

這個(gè)方法依然存在缺點(diǎn),這個(gè)單體對象的所有屬性和方法都是共有的,外部可隨時(shí)訪問和修改,于是采用閉包來模擬私有屬性和方法,如下:

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();
  }

  }

})();


在這里我們直接給該單體對象賦值了一個(gè)匿名自執(zhí)行的函數(shù),在該函數(shù)中使用var和function關(guān)鍵字分別來定義其私有屬性和方法,這些在函數(shù)外部(單體對象外部)是無法直接訪問的,因?yàn)楹瘮?shù)一執(zhí)行完畢,其內(nèi)部作用域的空間就會被回收,這也就是能夠利用閉包來模擬私有屬性和方法的原因所在。在該函數(shù)(閉包)中,同時(shí)最終返回一個(gè)對象,這個(gè)對象中包含一些公有方法和屬性,在外部可以直接調(diào)用,同時(shí)這些公有方法由于定義在函數(shù)內(nèi)部,所以可以調(diào)用其私有屬性和方法,但是外界只能通過返回的公有方法和屬性來完成某些操作,不能夠直接調(diào)用Singleton.privateMethod1這些屬性。這就使得該單體對象既隔離了外界去直接訪問其私有屬性和方法,又提供給外界一些共有屬性和方法去完成某些操作。

這種匿名函數(shù)自執(zhí)行所構(gòu)造的單體模式在很多js庫中被廣泛使用,但是依然存在一個(gè)問題,如果我們在載入頁面的時(shí)候并不需要用到該對象,而且該對象的創(chuàng)建比較耗費(fèi)開銷(如需要進(jìn)行大量計(jì)算或需要多次訪問dom樹及其屬性等)時(shí),合理的做法是需要它的時(shí)候再去創(chuàng)建它,而不是隨著js的解析執(zhí)行直接去創(chuàng)建,這種概念被稱之為惰性加載(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;
      }
    }

  })();

這里首先在匿名函數(shù)中定義了一個(gè)私有變量uniqueInstance,作為一個(gè)判斷單體對象是否被創(chuàng)建出來的句柄,然后將剛才所有對單體對象定義的屬性和方法都放在一個(gè)名為constructor的函數(shù)中,只有該函數(shù)調(diào)用了,才會創(chuàng)造出該單體對象,否則不會直接創(chuàng)建它。然后,返回一個(gè)對象,其包含一個(gè)getInstance方法,該方法是供外部調(diào)用的,調(diào)用該方法的時(shí)候首先判斷該單體對象是否存在,如果存在就直接返回它,否則調(diào)用constructor函數(shù)構(gòu)造這個(gè)單體對象再返回它。最后如果我們調(diào)用該單體對象的某個(gè)方法,需要使用mySpace.Singleton.getInstance().publicMethod1(),這里,只有我們這樣調(diào)用的時(shí)候才會創(chuàng)建這個(gè)單體對象,否則該單體對象是不會被自動創(chuàng)建的,這實(shí)際上就實(shí)現(xiàn)了按需加載或者惰性加載。

相關(guān)文章

最新評論