闭包实现单例模式的核心是将实例变量封在函数作用域内,外部无法直接访问或重置,确保所有调用都返回同一不可篡改的引用;通过IIFE封装instance、隐藏真实构造器、只暴露单一入口,并支持延迟初始化与运行时控制。

闭包实现单例模式的核心,在于把实例变量封在函数作用域内,外部无法直接访问或重置,同时确保构造逻辑只执行一次。关键不是“禁止 new”,而是让所有调用路径最终都落到同一个对象引用上,且这个引用不可篡改、不可绕过。
用 IIFE 封装私有 instance 变量
立即执行函数(IIFE)创建独立作用域,instance 作为闭包内变量,外界既不能读取也不能赋值:
- 声明一个内部变量 instance = null,仅在闭包中可见
- 返回一个工厂函数(或构造函数代理),每次调用时检查 instance 是否已存在
- 若不存在,才调用真正的构造逻辑(如 new MyClass() 或 createInstance())并赋值
- 若已存在,直接 return instance,不触发任何初始化行为
彻底隐藏真实构造器,防止外部绕过
只暴露单一入口,把类定义也放在闭包里,外部连类名都拿不到:
- 在 IIFE 内部定义 function ConfigManager() { ... },不抛出到全局
- 不导出 ConfigManager 构造函数,只导出 getInstance 或工厂函数
- 这样 new ConfigManager() 在外部会报错:ReferenceError
- 用户只能通过你提供的接口获取实例,没有第二条路
加一层防御:避免意外覆盖或误删
即使 instance 被返回出去,也要防止它被外部清空或重新赋值:
立即学习“Java免费学习笔记(深入)”;
- 返回前可用 Object.freeze(instance) 锁定对象属性(适用于配置类等只读场景)
- 不在闭包外暴露 instance 变量本身,只暴露它的副本或包装后的访问方法
- 如果需支持多次初始化(如带参数的懒加载),instance 判断逻辑要严格校验参数一致性,否则抛错而非覆盖
模块级单例更自然,但闭包版更可控
ES6 模块默认导出一个对象,本身就是单例,但它是“编译时单例”,无法做运行时控制(比如按需初始化、参数校验、错误重试)。而闭包方案可精确掌控:
- 首次调用 getInstance 才真正创建实例(延迟初始化)
- 可在 createInstance 中加入 try/catch 处理初始化失败
- 可记录是否已初始化、是否初始化失败,提供 isReady() 等状态方法
- 适合日志器、API 客户端、WebSocket 连接管理等需要精细生命周期控制的场景


















