[设计模式]单例模式在前端的应用及其ES5, ES6, TS实现

220 阅读1分钟

What-什么是单例模式

一个类只有单独的一个实例

Why-为什么要用单例模式

若重复创建不同的实例, 会导致全局管理数据/状态的丢失/混乱

Where-哪里用到单例模式

Vuex

let Vue // bind on install
// ...
export function install (_Vue) {
  if (Vue && _Vue === Vue) {
    if (process.env.NODE_ENV !== 'production') {
      console.error(
        '[vuex] already installed. Vue.use(Vuex) should be called only once.'
      )
    }
    return
  }
  Vue = _Vue
  applyMixin(Vue)
}

How-如何实现单例模式

ES5

静态方法与闭包实现

function SingletonClass () {}

SingletonClass.getInstance = (function() {
  var instance
  return function () {
    if (instance === undefined) {
      instance = new SingletonClass()
    }
    return instance
  }
})()

const s1 = SingletonClass.getInstance()
const s2 = SingletonClass.getInstance()
console.log(s1 === s2) // true

构造函数return实现

function SingletonBase () {}

function SingletonClass () {
  if (SingletonBase.instance === undefined) {
    SingletonBase.instance = new SingletonBase()
  }
  return SingletonBase.instance
}

const s1 = new SingletonClass()
const s2 = new SingletonClass()
console.log(s1 === s2) // true

ES6

class SingletonClass {
  constructor() {
    if (SingletonClass.Instance === undefined) {
        SingletonClass.Instance = this
    }
    return SingletonClass.Instance
  }
}

const s1 = new SingletonClass()
const s2 = new SingletonClass()
console.log(s1 === s2) // true

TypeScript

构造函数return实现

class SingletonClass {
  private static instance: SingletonClass

  constructor () {
    if (SingletonClass.instance === undefined) {
      SingletonClass.instance = this
    }
    return SingletonClass.instance
  }
}

const s1 = new SingletonClass()
const s2 = new SingletonClass()
console.log(s1 === s2) // true

装饰器实现

// 单例装饰器, 接收原始构造器
function singleton (rawConstructor: Function) {
  let instance

  // 新构造器
  const newConstructor: any = function (...args) {
    // 辅助构造器
    const assistConstructor: any = function assistConstructor () {
        return rawConstructor.apply(this, args)
    }
    // 继承原型属性和方法
    assistConstructor.prototype = rawConstructor.prototype
    if (instance === undefined) {
      instance = new assistConstructor()
    }
    return instance
  }

  // 继承原型属性和方法
  newConstructor.prototype = rawConstructor.prototype

  // 返回新构造器, 它将覆盖原构造器
  return newConstructor
}

@singleton
class SingletonClass {}

const s1 = new SingletonClass()
const s2 = new SingletonClass()
console.log(s1 === s2) // true