Skip to content

单例模式

单例定义

单例模式的定义就是:保证一个类只有一个实例,并提供一个访问他的全局站点

实现单例模式

我们只要用一个标识标记是否已经创建过对象,如果是,则在下一次获取时直接返回之前创建的实例

js
class User {
  constructor(name) {
    this.name = name
    this.instance = null
  }
  static getInstance(name) {
    if (!this.instance) {
      this.instance = new User(name)
    }
    return this.instance
  }
}

const user1 = User.getInstance('张三')
const user2 = User.getInstance('李四')

console.log(user2 === user1) // true

上面已经实现了一个简单的单例模式,但是这样意义并不是很大,下面一步步编写出更好的单例模式

透明单例

接下来来实现一个透明的单例模式,用户从这个类中创建对象的时候,可以像使用其他普通类一样进行使用

下面来实现创建一个唯一的 div 节点

js
class Render {
  constructor(html) {
    if (!Render.instance) {
      Render.instance = this
      this.html = html
      this.init()
    }
    return Render.instance
  }
  init() {
    const div = document.createElement('div')
    div.innerText = this.html
    document.body.appendChild(div)
  }
}

const node1 = new Render('hello')
const node2 = new Render('hello2')

console.log(node1 === node2) // true

这个,不管我们 new 多少次这个类,始终都是创建一个实例

使用代理实现单例

接下来使用代理方式,来再写一遍上面例子

js
// 渲染类
class CreateDiv {
  constructor(html) {
    this.html = html
    this.init()
  }
  init() {
    const div = document.createElement('div')
    div.innerText = this.html
    document.body.appendChild(div)
  }
}

// 代理类
class Render {
  constructor(html) {
    if (!Render.instance) {
      Render.instance = new CreateDiv(html)
    }
    return Render.instance
  }
}

const node1 = new Render('hello')
const node2 = new Render('hello-121')

console.log(node1 === node2) // true

惰性单例

惰性单例是在需要的时候再创建出对象实例。

惰性单例模式用在弹出框上面,下面就用一个提示框来展示一下惰性单例

html
<button id="btn">展示浮窗</button>
<script>
  const render = (function () {
    let div
    return function () {
      if (!div) {
        div = document.createElement('div')
        div.style.display = 'none'
        div.innerText = '这是一个提示框'
        document.body.appendChild(div)
      }
      return div
    }
  })()

  document.getElementById('btn').addEventListener('click', () => {
    const node = render()
    node.style.display = 'block'
  })
</script>

通用惰性单例

在上面例子中,我们在页面中创建了一个唯一的 div 元素,但是这个函数并不灵活,如果想要吧 div 改为 p 那么就要重写一遍这个函数,所以接下来要封装一个通用想惰性单例模式

js
function render(fn) {
  let instance
  return function () {
    return instance || (instance = fn())
  }
}

这样就抽离出了一个通用型的函数,接下来就可以这样使用:

html
<button id="btn">点击</button>
<script>
  function render(fn) {
    let instance
    return function () {
      return instance || (instance = fn())
    }
  }

  function createDiv() {
    const div = document.createElement('div')
    div.innerText = '这是一个 div'
    div.style.display = 'none'
    document.body.appendChild(div)
    return div
  }

  function createInput() {
    const input = document.createElement('input')
    input.style.display = 'none'
    document.body.appendChild(input)
    return input
  }

  const createRenderDiv = render(createDiv)
  const createRenderInput = render(createInput)

  document.getElementById('btn').addEventListener('click', () => {
    const div = createRenderDiv()
    const input = createRenderInput()
    div.style.display = 'block'
    input.style.display = 'block'
  })
</script>