所谓单例模式,就是保证类的实例只有一个。思路很清晰,就是在构造函数中置一个标志,或者已存在的实例对象。先来一道简单版:**

const f = function(name) {
  this.single = null
  this.name =name
}

f.getObj = function(name) {
  if(!this.single) {
    this.single =  new f(name)
    return this.single
  } else {
    return this.single
  }
}

const a = f.getObj('s1')
const b = f.getObj('s2')
console.log(a)
console.log(b)

// f { single: null, name: 's1' }
// f { single: null, name: 's1' }

这种实现方式其实很简单,实际上就是给构造函数f挂在了一个单独属性single,初次new时挂在上去之后,之后的每次new都是无效的,都会返回初次的那位。但是上述方法很是变扭,因为我们实例化通常都是用new而不是调用一个方法。为此,进行改进。

const f = function(html) {
  this.html = html
  this.single = null
}

f.prototype.init = function() {
  let div = document.createElement('div')
  div.innerHTML = this.html
  this.single = div
}

const proxy = (function() {
  let instance
  return function(html) {
    if(!instance) {
      instance = new f(html)
    }
    return instance  
  }
})()

const a = new proxy('s1')
const b = new proxy('s2')
console.log('a:', a)
console.log('b:', b)

// a: f {html: "s1", single: div}
// b: f {html: "s1", single: div}

因为闭包结构,使得只要调用proxy时,instance始终存在于当前环境,即唯一的那个实例。完美!

其他的经典设计模式

  • 发布订阅模式
    这个应该没什么好说的了,前端随处可见。例如:vue的响应式数据、eventbus等

  • 组合模式
    典型实现,就是前端开发组件的通用共识:组件化开发

  • 命令模式
    通知某对象执行某方法,但并不关注执行者是谁,以及执行的操作是什么。例如:函数的回调