深刻淺出js單例模式

何爲單例模式?顧名思義,單例模式就是保證一個類僅有一個實例,也就是建立出來的兩個實例必須相等!html

構造函數靜態屬性建立單例

function Singleton() {
      // 已有實例則返回該實例,沒有則建立實例
      if (typeof Singleton.instance === 'object') {
        return Singleton.instance
      }
      // 把本身綁定到insta靜態屬性上,保證每次建立相同實例
      Singleton.instance = this
    }
    var sigle1 = new Singleton()
    var sigle2 = new Singleton()
    console.log(sigle1 === sigle2)  // true 兩個實例相等
    sigle1.instance = 123
    console.log(sigle2.instance) // 123

該方法的缺點是,instance屬性暴露外面,改變一個實例的屬性,另外一個也會跟着改變! 實例sigle1.instance的改變的同時sigle2.instance也跟着同時也變化了,這不是咱們但願要的結果!設計模式

構造函數建立不透明單例

const Singleton = function (name) {
      this.name = name
      this.instance = null
    }
    Singleton.getInstance = function (name) {
      // 單例已建立則返回,未建立則建立並返歸
      return this.instance || (this.instance = new Singleton(name))
    }
    Singleton.prototype.getName = function () {
      return this.name
    }
    var instance1 = Singleton.getInstance('instance1')
    var instance2 = Singleton.getInstance('instance2')
    console.log(instance1 === instance2) // true 兩個實例相等
    console.log(instance1.getName(), instance2.getName()) // instance1 instance1

和上一個案例相似,利用構造函數的靜態熟悉存儲單例,可是該單例並不能改變instance屬性。然而,該方法建立單例具備不透明性,須要具體告知用戶如何使用。閉包

利用閉包建立單例

function Singleton() {
      var Man = function (name) {
        this.name = name
      }
      var instance
      // 函數中返回函數,且返回函數中佔用instance,造成閉包,instance惟一
      return function (arg) {
        if (!instance) {
          instance = new Man(arg)
        }
        return instance
      }
    }
    var single = Singleton()
    console.log(single('tom') === single('jack')) // true 兩個實例相等

和上面一個案例同樣,用閉包建立單例具備不透明性,並且容易形成內存泄漏。好了說了這麼多實現單例的方式,接下來講說單例在工做中的具體使用狀況。app

單例的實際使用

咱們html頁面中的提示遮罩框就可使用單例來建立,由於建立一次,重複使用,不必再次建立相同遮罩框。這邊我就不寫具體遮罩框的樣式了,嘿嘿。函數

//  在html頁面建立點擊按鈕
    
    <button id="app">點我建立單例</button>
// 利用當即執行函數建立遮罩框layer
    var creatLayer = (function(innerHTML){
      var layer
      return function(innerHTML){
        if(!layer){
          layer = document.createElement('div')
          layer.innerHTML = innerHTML
          layer.style.display = 'none'
          document.body.appendChild(layer)
        }
        return layer
      }
    })()
    // 點擊按鈕彈出遮罩框
    document.getElementById('app').onclick = function(){
      var layer = creatLayer('我是遮罩框')
      layer.style.display = 'block'
    }

不管按鈕點擊多少次,始終只有建立一個遮罩框,從而避免重複建立。不過邊creatLayer函數中含有大量業務代碼。遵循高內聚,低耦合的思想,咱們進行改造!this

// 把業務代碼寫到creatLayer函數
    var creatLayer = function (innerHTML) {
      var layer = document.createElement('div')
      layer.innerHTML = innerHTML
      layer.style.display = 'none'
      document.body.appendChild(layer)
      return layer
    }
    // 單例單例判斷交給getSingle函數,和業務邏輯分開
    var getSingle = function (fn) {
      var div
      return function () {
        return div || (div = fn.apply(this, arguments))
      }
    }
    var layer = getSingle(creatLayer)
    document.getElementById('app').onclick = function () {
      var div = layer('我是遮罩框')
      div.style.display = 'block'
    }

好了,單例模式具體介紹到這裏了。若是想看更多的設計模式,能夠看我晚期設計模式系列文章。若是以爲對你有幫助的話,記得給個贊哈😃prototype

相關文章
相關標籤/搜索