JavaScript设计模式——单例模式

464 阅读2分钟

一个类只允许有一个实例,并且可以全局访问该实例 单例模式在实际开发中经常会用到,如用户点击弹出层,保持始终只有一个弹出层实例。下面我们循序渐进,先写一个最简单的单例

最简单的单例

我们用闭包延长作用域链,保存一个实例

const Single = function (name) {
  this.name = name
}
Single.prototype.log = function () {
  console.log(this.name)
}

Single.getInstance = (function () {
  let instance = null
  return function (name) {
    if (!instance) {
      instance = new Single(name)
    }
    return instance
  }
})()

const tom = Single.getInstance('tom')
const bob = Single.getInstance('bob')
console.log(tom==bob);  //true
  1. 首次getInstance的时候,没有实例,创建实例并保存;
  2. 再次getInstance,已经有实例,直接返回实例;

构造单例

上面创建单例的方式可能不是很直观,对于用户来说,至少需要知道通过Single.getInstance创建/访问单例子。我们采用更习惯的构造函数模式重构一下

const Single = (function () {
  let instance = null
  const CreateSingle = function (name) {
    if (instance) {
      return instance
    }
    this.name = name
    return (instance = this)
  }
  CreateSingle.prototype.log = function () {
    console.log(this.name)
  }
  return CreateSingle
})()
const tom = new Single('tom')
const bob = new Single('bob')
console.log(tom == bob) //true

单例代理

如果实际开发中需要很多单例模型,那我们就需要创建很多个单例类。我们是不是可以把单例管理的内容抽离出来呢?反正我们关心的只是一个类只有一个实例就行了,并不关心这个怎么保证生成单个实例。单例代理就是把保证只创建一个实例的逻辑抽离出来,开发者只需要创建单例类就行

//代理
const getSingle = function (fn) {
  let result = null
  return function () {
    return result || (result = fn.apply(this, arguments))
  }
}

那么接下来我们只需要传入单例类即可生成对应的单例了

//createDIV
const createDIV = function () {
  const div = document.createElement('div')
  div.innerHTML = '登录弹窗'
  document.appendChild(div)
  return div
}
const createSingleDiv = getSingle(createDIV)


//createText
const createText = function(content) {
  const text = document.createTextNode(content)
  return text
}
const createSingleText = getSingle(createText)