JavaScript 单例模式:用静态属性保证 Popup 只创建一次

在 JavaScript 中,很多初学者会把单例模式理解成"只能 new 一次"。更准确的说法是:把实例的创建和获取集中到一个入口,让业务代码共享同一个对象。

本文根据一个 Popup 示例解释 staticgetInstance()a === b 的逻辑,并指出当前示例存在的一个可运行性问题。源码静态阅读,运行未验证

单例示例的目标

代码希望让所有"打开网页"的操作共用一个 Popup 对象,而不是每次点击按钮都:

js 复制代码
new Popup();

核心实现:

js 复制代码
class Popup {
  static ins;

  static getInstance() {
    if (!Popup.ins) {
      Popup.ins = new Popup();
    }
    return Popup.ins;
  }
}

static ins 保存唯一实例

static ins 是类属性,访问方式是:

js 复制代码
Popup.ins

而不是:

js 复制代码
somePopup.ins

它负责保存已经创建好的对象。第一次获取实例时它为空;创建完成后,它指向唯一的 Popup 对象。

getInstance() 控制创建时机

js 复制代码
static getInstance() {
  if (!Popup.ins) {
    Popup.ins = new Popup();
  }
  return Popup.ins;
}

调用流程:

text 复制代码
第一次 getInstance()
  → ins 不存在
  → new Popup()
  → 保存到 Popup.ins
  → 返回实例

第二次 getInstance()
  → ins 已存在
  → 不再 new
  → 返回原来的实例

这就是延迟创建:只有真正需要对象时才创建。

为什么 a === b 为 true

js 复制代码
const a = Popup.getInstance();
const b = Popup.getInstance();
console.log(a === b); // true

对象变量保存的是引用。ab 都拿到 Popup.ins,所以严格比较的结果为 true

这不是两个内容相同的对象,而是两个变量指向同一个对象。

按钮事件如何使用单例

js 复制代码
const openBtn = document.getElementById("openBtn");
openBtn.addEventListener("click", () => {
  a.open("https://www.baidu.com");
});

按钮点击时,事件回调调用 a.open()。设计意图是让 Popup 类统一管理打开网页这件事,而不是把逻辑散落在不同的点击事件中。

当前示例的关键问题

Popup 类中没有 open() 方法,但按钮事件调用了:

js 复制代码
a.open("https://www.baidu.com");

因此点击按钮时可能报错:

text 复制代码
TypeError: a.open is not a function

被注释的代码:

js 复制代码
window.open("https://www.baidu.com ", "_blank");

说明作者原本想让 Popup.open() 内部调用 window.open();但这个方法还没有实现。_blank 通常表示在新标签页或新窗口中打开页面。

单例模式排查清单

检查项 正确状态
是否有缓存实例的静态属性 例如 static ins
是否有统一获取入口 例如 static getInstance()
创建逻辑是否只在实例不存在时触发 if (!Popup.ins)
所有业务代码是否通过入口获取实例 Popup.getInstance()
调用的方法是否真的定义在类中 当前 open() 未定义
是否直接绕过入口执行 new Popup() 当前代码未限制,需要团队约定

面试怎么说

可以这样回答:

单例模式通过一个静态属性保存实例,并通过静态方法统一获取。第一次调用时创建实例,后续调用直接复用,因此适合管理配置、缓存、日志或模型等全局共享资源。JavaScript 中还要注意:如果构造函数没有额外限制,外部仍可以直接 new,所以单例通常依赖封装和使用约定。

结语

理解单例模式,不要只记"只创建一个对象"。重点是理解:谁负责创建、实例存在哪里、后续如何复用、业务代码是否绕过统一入口。

下一步可以给 Popup 补上 open() 方法,再在浏览器中验证按钮是否能打开新页面。本文未执行项目,运行结果未验证。

标签: JavaScript, 设计模式, 单例模式, DOM

相关推荐
No Silver Bullet2 小时前
Vue进阶(贰幺叁)vue.config.js 中 productionSourceMap 作用详解
前端·javascript·vue.js
用户847181054193 小时前
LangChain中间件教程及DeepAgents应用
javascript·agent
huabuyu3 小时前
INP 自动化归因与自愈:如何自动定位、修复并验证一次卡顿
前端·javascript
BreezeJiang3 小时前
浏览器里的 DeepSeek 到底怎么跑起来?关键在 Worker、缓存和流式消息
javascript
BreezeJiang3 小时前
单例模式真正解决的不是“只能 new 一次”,而是统一资源入口
javascript
snow@li3 小时前
SpringBoot:AOP日志切面全景梳理/原理+流程+实战+避坑
java·开发语言·spring boot
Nil2083 小时前
C++ emplace_back 与 push_back 详解
开发语言·c++
小林ixn3 小时前
WebGPU + Transformers.js:把 DeepSeek-R1 塞进浏览器,真香!
javascript·llm·gpu
xiaominlaopodaren3 小时前
three.js地图数学基础(四):瓦片金字塔
javascript·gis·three.js