從JavaScript學習設計模式-02單例模式

huangjincq發表於2019-02-23

保證一個類僅有一個例項,並且提供一個訪問它的全域性訪問點

單例模式的思路是:一個類能返回一個物件的引用(並且永遠是同一個)和一個獲得該例項的方法(靜態方法,通常使用 getInstance 名稱)。那麼當我們呼叫這個方法時,如果類持有的引用不為空就返回該引用,否者就建立該類的例項,並且將例項引用賦值給該類保持的那個引用再返回。同時將該類的建構函式定義為私有方法,避免其他函式使用該建構函式來例項化物件,只通過該類的靜態方法來得到該類的唯一例項。

應用場景

日常開發中,經常製作彈窗的時候我們需要一個半透明的遮罩層,為了減少不必要的dom操作,我們正確的思路應該是,判斷有沒有生成過這個 model div 如果已經生成了就不必再次生成。

實現步驟

步驟1 寫一個生成 model div的方法

   <style>
    .modal {
      position: fixed;
      left: 0;
      top: 0;
      width: 100%;
      height: 100%;
      opacity: .5;
      background: #000;
      z-index: 99;
    }
  </style>
  
 <script>
  function createModal () {
    const div = document.createElement(`div`);
    div.className = `modal`;
    document.body.appendChild(div);
  }

  createModal()  
  createModal()  // 呼叫兩次 將會產生兩個模態框
</script>  

複製程式碼

呼叫兩次 createModal 方法將會產生在body上追加兩個div 很顯然不是我們需要的結果,我們需要增加一個變數判斷是否已經呼叫過

根據單例模式的定義來實現

  1. 保證一個類僅有一個例項 new createModal()
  2. 並且提供一個訪問它的全域性訪問點 createModal.getInstance 方法訪問
  function createModal () {
    const div = document.createElement(`div`);
    div.className = `modal`;
    document.body.appendChild(div);
  }

  createModal.getInstance = function () {
    if (this.instace) {
      return this.instace;
    } else {
      this.instace = new createModal(); 
      return this.instace;
    }
  };
  const a = createModal.getInstance()
  const b = createModal.getInstance() // 呼叫兩次 例項一次
  console.log(a === b)  // true
複製程式碼

此段程式碼就根據單例模式的定義來用js實現了一個單例模式,呼叫多次也只會例項一個 createModal ,生成一個模態框

惰性單例

由於js的特性,可用閉包的形式保護一個私有變數,讓他來作為判斷值,並且惰性函式代表:在需要的時候才建立物件例項,而非在頁面載入時就建立

  const createModal = (function(){
    let div;
    return function(){
      if(!div){
        div = document.createElement(`div`);
        div.className = `modal`;
        document.body.appendChild(div);
      }
    }
  })();
  createModal()
  createModal() // 呼叫兩次 div 生成一次

複製程式碼

通過閉包,保護了 div 變數,在呼叫時候判斷

通用模式

通過上面程式碼我們發現如果需要新建另外一個div,只能複製程式碼,是否能想辦法把 return 裡生成div 的方法分離出來呢。

  1. 建立一個 getSingle 方法 result 為判斷變數
  2. 建立一個 createModal 的方法為具體執行程式碼,並且返回一個bool值給 getSingle 中的 result 進行判斷
  const getSingle = function (fn) {
    let result;
    return function () {
      return result || (result = fn.apply(this, arguments));
    }
  };
  const createModal = function () {
    const div = document.createElement(`div`);
    div.className = `modal`;
    document.body.appendChild(div);
    return div
  }
  const createSingleDiv = getSingle(createModal)
  const a = createSingleDiv()
  const b = createSingleDiv()
  console.log(a === b)  // true
複製程式碼

這樣就建立了一個 建立惰性單例的通用模式了

總結

單例模式在實際開發中應用很多,特別是在框架設計,合理利用可以提高效能。

相關文章