成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐 | 04 - 單例模式

awkj / 2590人閱讀

摘要:觀察構(gòu)造函數(shù)的代碼,該構(gòu)造函數(shù)實(shí)際上負(fù)責(zé)了兩件事情第一是創(chuàng)建對象和執(zhí)行初始化方法,第二是保證只有一個(gè)對象。惰性單例在實(shí)際開發(fā)中非常有用,是單例模式的重點(diǎn)。

單例模式

單例模式的定義是:

保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。

單例模式是一種常用的模式,有一些對象我們往往只需要一個(gè),比如線程池、全局緩存、瀏覽器的window對象等。例如,當(dāng)我們點(diǎn)擊登錄按鈕時(shí),頁面會(huì)彈出一個(gè)登錄懸浮窗,而這個(gè)登錄懸浮窗是唯一的,無論點(diǎn)擊多少次登錄按鈕,這個(gè)懸浮窗只會(huì)被創(chuàng)建一次,這時(shí),這個(gè)懸浮窗就適合用單例模式來創(chuàng)建。

實(shí)現(xiàn)單例模式

實(shí)現(xiàn)一個(gè)標(biāo)準(zhǔn)的單例模式,一般是用一個(gè)變量來標(biāo)志當(dāng)前是否已經(jīng)為某個(gè)類創(chuàng)建過對象,若是,則在下一次獲取該類的實(shí)例時(shí),直接返回之前創(chuàng)建的對象。

不透明的單例模式
var Singleton = function(name){
  this.name = name;
  this.instance = null;
}

Singleton.prototype.getName = function(){
  console.log(this.name);
};

Singleton.getInstance = function(name){
  if(! this.instance){
      this.instance  = new Singleton(name);
  }
  return this.instance;
};

var a = Singleton.getInstance("sin1");
var b = Singleton.getInstance("sin2");

console.log(a === b);  // 輸出:true

我們通過Singleton.getInstance來獲取Singleton類的唯一對象,這種方式想對簡單,但有一個(gè)問題,就是增加了類的“不透明性”,Singleton類的使用者必須知道這是一個(gè)單例類,跟以往通過new xxx來獲取對象的方式不同,這里只能使用Singleton.getInstance來獲取對象。

透明的單例模式

現(xiàn)在我們通過一段代碼來實(shí)現(xiàn)一個(gè)透明的單例類,用戶從這個(gè)類中創(chuàng)建對象的時(shí)候,可以像使用其他任何普通類一樣。

var createDiv = (function(){
  var instance;

  var createDiv = function(html){
      if(instance){
        return instance;
      }

      this.html = html;
      this.init();
      return instance = this;
  };

  createDiv.prototype.init = function(){
      var div = document.createElement("div");
      div.innerHTML = this.html;
      document.body.appendChild(div);
  };

  return createDiv;
})();

var a = new createDiv("sin1");
var b = new createDiv("sin2");

console.log(a === b);  // 輸出:true

為了把instance封裝起來,我們使用了自執(zhí)行的匿名函數(shù)和閉包,并且讓這個(gè)匿名函數(shù)返回真正的Singleton構(gòu)造方法,這增加了一些程序的復(fù)雜度,閱讀起來也不是很舒服。

觀察Singleton構(gòu)造函數(shù)的代碼,該構(gòu)造函數(shù)實(shí)際上負(fù)責(zé)了兩件事情:第一是創(chuàng)建對象和執(zhí)行初始化init方法,第二是保證只有一個(gè)對象。這不符合設(shè)計(jì)原則中的“單一職責(zé)原則”,這是一種不好的做法。假設(shè)我們某天需要利用這個(gè)類,在頁面中創(chuàng)建很多個(gè)div,即讓這個(gè)類從單例類編程一個(gè)普通的可以產(chǎn)生多個(gè)實(shí)例的類,我們就得改寫createDiv構(gòu)造函數(shù),把控制創(chuàng)建唯一對象的那一段去掉,這種修改會(huì)給我們帶來不必要的煩惱。

用代理實(shí)現(xiàn)單例模式

現(xiàn)在我們通過引入代理類的方法,來解決上面提到的問題。

var createDiv = function(html){
  this.html = html;
  this.init();
};

createDiv.prototype.init = function(){
  var div = document.createElement("div");
  div.innerHTML = this.html;
  document.body.appendChild(div);
};

// 引入代理類 proxySingletonCreateDiv
var proxySingletonCreateDiv = (function(){
  var instance;
  return function(html){
      if(!instance){
        instance = new createDiv(html);
      }
      return instance;
  }
})();

var a = new proxySingletonCreateDiv("sin1");
var b = new proxySingletonCreateDiv("sin2");

我們把負(fù)責(zé)管理單例的邏輯移到了代理類proxySingletonCreateDiv中。這樣一來,createDiv就變成了一個(gè)普通的類,它跟proxySingletonCreateDiv組合起來就可以達(dá)到單例模式的效果;如果多帶帶使用,就作為一個(gè)普通的類,能產(chǎn)生多個(gè)實(shí)例對象。

JavaScript中的單例模式

前面提到的單例模式的實(shí)現(xiàn),更多的是接近傳統(tǒng)面向?qū)ο笳Z言中的實(shí)現(xiàn),單例對象從類中創(chuàng)建而來。在以類為中心的語言中,這是很自然的做法,比如在Java中,如果需要某個(gè)對象,就必須先定義一個(gè)類,對象總是從類中創(chuàng)建而來。

但JavaScript是一門無類語言,生搬單例模式的概念并無意義。在JavaScript中創(chuàng)建對象非常簡單,直接聲明即可。既然這樣,我們就沒有必要為它先創(chuàng)建一個(gè)類。

單例模式的核心是確保只有一個(gè)實(shí)例,并提供全局訪問。

全局變量不是單例模式,但在JavaScript開發(fā)中,我們經(jīng)常會(huì)把全局變量當(dāng)成單例模式來使用,例如var a = {};

當(dāng)用這種方式創(chuàng)建對象a時(shí),對象a確實(shí)獨(dú)一無二。如果變量a被聲明在全局作用域下,則我們可以在代碼中的任何位置使用這個(gè)變量,全局變量自然能全局訪問。這樣就滿足了單例模式的兩個(gè)條件。

但是,全局變量存在一些問題:

容易造成命名空間污染;

在大型項(xiàng)目中,如果不加以限制和管理,程序中可能存在很多這樣的變量;

JavaScript中的變量很容易被不小心覆蓋。

因此,在使用全局變量時(shí),我們要盡力降低它的污染,通過以下方式:

1.使用命名空間
適當(dāng)?shù)厥褂妹臻g,并不會(huì)杜絕全局變量,但可以減少全局變量的數(shù)量。
最簡單的方法依然是用對象字面量的方式:

var namespace1 = {
  a: function(){
      alert(1);
  },
  b: function(){
      alert(2);
  }
};

把a(bǔ)和b都定義為namespace1的屬性,這樣可以減少變量和全局作用域打交道的機(jī)會(huì)?!?/p>

另外,可以動(dòng)態(tài)地創(chuàng)建命名空間,如:

var myApp = {};

myApp.namespace = function(name){
  var parts = name.split(".");
  var current = myApp;
  for(var i in parts){
      if(!current[parts[i]]){
          current[parts[i]] = {};
      }
      current = current[parts[i]];
  }
};

myApp.namespace("event");
myApp.namespace("dom.style");

上述代碼等價(jià)于:

var myApp = {
  event:{},
  dom:{
    style:{}
  }
};

2.使用閉包封裝私有變量
這種方法把一些變量封裝在閉包的內(nèi)部,只暴露一些接口跟外界通信:

var user = (function(){
  var __name = "sin1";
  var __age = 29;

  return {
      getUserInfo: function(){
          return __name + "-" + __age;
      }
  }
})();

我們用下劃線來約定私有變量__name和__age,它們被封裝在閉包產(chǎn)生的作用域中,外部是訪問不到這兩個(gè)變量的,這就避免了對全局的命名污染。

惰性單例

惰性單例指的是在需要的時(shí)候才創(chuàng)建對象實(shí)例。惰性單例在實(shí)際開發(fā)中非常有用,是單例模式的重點(diǎn)。

我們在開頭寫的Singleton類就用過這種技術(shù),instance實(shí)例對象總是在我們調(diào)用Singleton.getInstance的時(shí)候才被創(chuàng)建,而不是在頁面加載好的時(shí)候就創(chuàng)建。

實(shí)現(xiàn)惰性單例

假設(shè),在一個(gè)提供登錄功能(點(diǎn)擊登錄按鈕彈出一個(gè)登錄懸浮窗)的web頁面中,可能用戶在訪問過程中,根本不需要進(jìn)行登錄操作,只需要瀏覽某些內(nèi)容。所以,沒有必要在頁面加載好之后就馬上創(chuàng)建登錄懸浮窗,只需要當(dāng)用戶點(diǎn)擊登錄按鈕的時(shí)候才開始創(chuàng)建登錄懸浮窗,實(shí)現(xiàn)代碼如下:




  惰性單例


  




但這段代碼還是存在一些問題的:

這段代碼仍然是違反單一職責(zé)原則的,創(chuàng)建對象和管理單例的邏輯都放在createLoginLayer對象內(nèi)部;

如果我們下次需要?jiǎng)?chuàng)建頁面中唯一的iframe,或者script標(biāo)簽,必須得如法炮制,把createLoginLayer函數(shù)幾乎照抄一遍。

通用的惰性單例

為了解決上面的問題,我們可以實(shí)現(xiàn)一段通用的惰性單例代碼:




  惰性單例


  




上面的代碼,

把管理單例的邏輯抽象了出來:用一個(gè)變量來標(biāo)志是否創(chuàng)建過對象,如果是,則在下次直接返回這個(gè)已經(jīng)創(chuàng)建好的對象;

把如何管理單例的邏輯封裝在getSingle函數(shù)內(nèi)部,創(chuàng)建對象的方法fn被當(dāng)成參數(shù)動(dòng)態(tài)傳入getSingle函數(shù);

將創(chuàng)建登錄懸浮窗的方法傳入getSingle,還能傳入createIframe,createScript;

getSingle函數(shù)返回一個(gè)新的函數(shù),并且用一個(gè)變量result來保存fn的計(jì)算結(jié)果,result變量在閉包中,永遠(yuǎn)不會(huì)被銷毀,所以在將來的請求中,如果result已經(jīng)被賦值,那么它將返回這個(gè)值。

單例模式的用途不止在于創(chuàng)建對象,比如我們通常渲染完頁面中的一個(gè)列表后,就要給這個(gè)列表綁定click事件,如果通過ajax動(dòng)態(tài)往列表里追加數(shù)據(jù),在使用事件代理的前提下,click事件實(shí)際上只需要在第一次渲染列表的時(shí)候就被綁定一次。




  惰性單例


  




PS:本節(jié)內(nèi)容為《JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》第四章 筆記。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/86213.html

相關(guān)文章

  • JavaScript設(shè)計(jì)模式開發(fā)實(shí)踐系列之單例模式

    摘要:本系列為設(shè)計(jì)模式與開發(fā)實(shí)踐作者曾探學(xué)習(xí)總結(jié),如想深入了解,請支持作者原版單例模式實(shí)現(xiàn)單例模式單例模式的定義是保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。 本系列為《JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》(作者:曾探)學(xué)習(xí)總結(jié),如想深入了解,請支持作者原版 單例模式 實(shí)現(xiàn)單例模式 單例模式的定義是:保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。單例模式是一種常用的模式...

    Airy 評論0 收藏0
  • JavaScript設(shè)計(jì)模式開發(fā)實(shí)踐 - 單例模式

    摘要:引言本文摘自設(shè)計(jì)模式與開發(fā)實(shí)踐在傳統(tǒng)開發(fā)工程師眼里,單例就是保證一個(gè)類只有一個(gè)實(shí)例,實(shí)現(xiàn)的方法一般是先判斷實(shí)例存在與否,如果存在直接返回,如果不存在就創(chuàng)建了再返回,這就確保了一個(gè)類只有一個(gè)實(shí)例對象。 引言 本文摘自《JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》 在傳統(tǒng)開發(fā)工程師眼里,單例就是保證一個(gè)類只有一個(gè)實(shí)例,實(shí)現(xiàn)的方法一般是先判斷實(shí)例存在與否,如果存在直接返回,如果不存在就創(chuàng)建了再返...

    QiShare 評論0 收藏0
  • javascript設(shè)計(jì)模式開發(fā)實(shí)踐全書深度解析(一)之單例模式

    摘要:所以程序在引入文件的時(shí)候用了單例模式,一個(gè)文件實(shí)例化一次,這種做法無疑是好的,但是也容易引起。在我們平時(shí)的開發(fā)過程中,可以借鑒這兩種方式去緩存變量,節(jié)點(diǎn)等。 這一章作者講了一個(gè)例子,就是在用單例模式生成一個(gè)dom節(jié)點(diǎn),還要做到只有訪問的時(shí)候才創(chuàng)建,后續(xù)訪問直接用前面創(chuàng)建的。那么實(shí)際開發(fā)中我們會(huì)用到這個(gè)模式嗎?現(xiàn)在我們基本都是用vue,react,angular開發(fā),不太會(huì)直接去操作do...

    xioqua 評論0 收藏0
  • JavaScript設(shè)計(jì)模式開發(fā)實(shí)踐》讀書筆記

    摘要:訂閱模式的一個(gè)典型的應(yīng)用就是后面會(huì)寫一篇相關(guān)的讀書筆記。享元模式享元模式的核心思想是對象復(fù)用,減少對象數(shù)量,減少內(nèi)存開銷。適配器模式對目標(biāo)函數(shù)進(jìn)行數(shù)據(jù)參數(shù)轉(zhuǎn)化,使其符合目標(biāo)函數(shù)所需要的格式。 設(shè)計(jì)模式 單例模式 JS的單例模式有別于傳統(tǒng)面向?qū)ο笳Z言的單例模式,js作為一門無類的語言。使用全局變量的模式來實(shí)現(xiàn)單例模式思想。js里面的單例又分為普通單例和惰性單例,惰性單例指的是只有這個(gè)實(shí)例...

    Panda 評論0 收藏0
  • JavaScript 設(shè)計(jì)模式(一):單例模式

    摘要:停更許久,近期計(jì)劃更新設(shè)計(jì)模式系列。單例模式是創(chuàng)建型設(shè)計(jì)模式的一種。雖然它不是正規(guī)的單例模式,但不可否認(rèn)確實(shí)具備類單例模式的特點(diǎn)。適用場景單例模式的特點(diǎn),意圖解決維護(hù)一個(gè)全局實(shí)例對象。 停更許久,近期計(jì)劃更新:設(shè)計(jì)模式系列。 showImg(https://segmentfault.com/img/bVbt7uw?w=800&h=600); 單例模式:限制類實(shí)例化次數(shù)只能一次,一個(gè)類只...

    xialong 評論0 收藏0

發(fā)表評論

0條評論

awkj

|高級講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<