JavaScript 设计模式实战:单例模式实现全局弹框

71 阅读3分钟

前言:从 JavaScript 函数的"二义性"说起

在深入单例模式之前,我们需要理解 JavaScript 中函数的一个有趣特性——二义性。这种特性既是 JavaScript 灵活性的体现,也是许多困惑的源头。

什么是函数的二义性?

function Person(){
    this.name='汉堡'
    return  'dssd'
}
let p=new Person()//创建一个实例对象{name:'汉堡'}
let s=Person()//创建一个函数体

很显然上面这个Person这个函数有两层用法一种是直接当成函数体来调用,还有一种就是直接用new来调用它,导致会创建一个实例对象。所以很多初学者就会觉得非常奇怪,于是在ECMAScript 6这个版本中官方打造了新的方法叫做类,我们现在就可以直接这样写,来消除函数的二义性。

class Person{//类

    constructor()
    {
    this.name='学生'
    }
}
let p=new Person()

这样得到的p就是一个实例对象

单例模式:确保唯一性

单例模式:保证一个类只有一个实例,并提供一个访问它的全局作用点。这段话说的太官方了,我们直接上代码

class Person{//类

    constructor(){
    this.name='学生'
    }
}
let p=new Person()
let s=new Person()
console.log(p==s);//false

这里我创建了一个Person这个类,并且通过new来生成了两个实例对象sp,很显然它们并不相同,因为每次都申请了一个不同的地址来创建这个实例对象。这时候我想这类每次生成地实例对象都是同一个,就可以通过static和闭包来创建一个单例模式。

static

  • 在 JavaScript 中,static 是一个关键字,用于定义类的静态属性和静态方法。静态成员属于类本身,而不是类的实例。
class Dog{
    
    show(){
        console.log('单例');   
    }
    static get(){
        if(!Dog.get){
            Dog.get=new Dog()
        }
        return Dog.get
    }
}
let p1=Dog.get
let p2=Dog.get
console.log(p1==p2);//ture

这里get函数每次返回的就都是同一个实例对象,静态函数只能被类访问,而不能被它的实例对象访问。

闭包

  • 当调用一个外部函数中返回的内部函数后,即使外部函数执行结束,但是内部函数依然引用了外部函数的变量,那么外部函数的执行上下文就不能完全销毁,而是会保留一个集合,用来装内部函数需要引用的变量,我们把集合称之为闭包。
class SingleDog {
  show() {
    console.log('我是一个单例对象');
  }
}
SingleDog.getInstance = (function() {
    let instance=new SingleDog()
  return function() {   
     return instance
  }
})()


const s1 = SingleDog.getInstance()
const s2 = SingleDog.getInstance()

console.log(s1 === s2);

这时候函数function返回的就是同一个实例对象instance

实现单例弹窗

就是让你写一个带有单例模式的弹窗,让你每次无论点哪个按钮关闭或者打开弹窗都是同一个弹窗。代码如下先写

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>单例弹框</title>
  <style>
    #modal {
      width: 200px;
      height: 200px;
      line-height: 200px;
      position: fixed;
      left: 50%;
      top: 50%;
      transform: translate(-50%, -50%);
      border: 1px solid #000;
      text-align: center;
    }
  </style>
</head>

<body>
  <button id="btn1">open1</button>
  <button id="btn2">open2</button>
  <button id="close">close</button>

  <script>
    const Modal = (function () {
      let modal = null
      return function () {
        if (!modal) {
          modal = document.createElement('div')
          modal.innerHTML = '我是一个全局弹框'  // <div id="modal">我是一个全局弹框</div>
          modal.id = 'modal'
          modal.style.display = 'none'
          document.body.appendChild(modal)  // 
        }
        return modal
      }
    })()

    document.getElementById('btn1').addEventListener('click', function () {
      const modal = new Modal()
      modal.style.display = 'block'
    })
    document.getElementById('btn2').addEventListener('click', function () {
      const modal = new Modal()
      modal.style.display = 'block'
    })
    document.getElementById('close').addEventListener('click', function () {
      const modal = new Modal()
      modal.style.display = 'none'
    })
  </script>
</body>

</html>

就是先创建三个按钮,再写一个弹窗里面带有单例模式先隐藏,最后给每个按钮绑定一个点击事件,这样每次打开关闭弹窗就是同一个

屏幕截图 2025-11-29 142558.png

总结

熟悉的掌握单例模式可以让代码更加美观简洁,提高代码质量,可读性,在实际应用场景中,同样也有很多地方用得上单例模式,这同样也是高频面试考点