模块模式用闭包实现单例懒初始化,即首次调用getinstance时才执行构造逻辑、创建实例并缓存,确保唯一性、节省内存;支持同步与异步依赖,且必须通过===验证同一引用。

模块模式用闭包实现单例的懒初始化,关键在于把实例创建推迟到第一次调用时,而不是模块加载就执行。它靠 IIFE 封装私有变量,用 延迟判断 + 闭包持有 确保只初始化一次,且不占初始内存。
闭包封装私有实例变量
实例变量必须定义在 IIFE 内部,不能暴露到模块顶层。这样外部无法绕过接口直接修改或重建,保证了唯一性来源可控。
- 用
let instance = null声明,避免var提升导致多次初始化 - 构造逻辑(如
createInstance())不能提前执行,必须放在getInstance的条件分支里 - 返回的对象只暴露
getInstance方法,不导出工厂函数或构造器
首次调用才真正创建对象
懒初始化不是“看起来懒”,而是构造函数完全不执行,直到第一次 getInstance() 被调用。DOM 操作、大型数组、事件绑定、网络请求等资源,全都不提前分配。
- 页面加载完但没触发登录弹窗 → 弹窗类不生成任何 DOM 节点
- 日志器未被使用 →
logs: []数组和定时格式化逻辑都不运行 - 配置管理器未调用 → 远程 fetch 或本地 storage 读取完全跳过
支持异步依赖的懒加载
当初始化需要等待 Promise(比如拉取 i18n 语言包或服务端配置),不能每次调用都发起新请求。应缓存 Promise 本身,而非结果值。
- 首次调用返回
Promise<instance></instance>,后续调用直接返回同一个 Promise - 避免重复请求:即使并发多次
getInstance(),底层只发一次 fetch - 错误可被捕获一次,后续调用仍可 await 同一个失败的 Promise
验证是否真为单例
仅结构相似不够,必须确认两次获取的是同一内存引用。这是唯一可信的检验方式。
- 写测试:
const a = Singleton.getInstance(); const b = Singleton.getInstance(); console.assert(a === b) - 避免陷阱:不要在
getInstance里每次都return new XXX(),也不要让instance被 HMR 或多模块导入重置 - 开发期可加
reset()方法辅助测试,但生产环境不暴露











