闭包通过IIFE将实例变量锁在私有作用域内,仅暴露受控方法,使外部无法访问、修改或枚举该变量,实现真正不可见的单例封装。

闭包在单例模式中实现“完全封装和隐藏全局唯一实例”的关键,是把实例变量锁在函数作用域内,不暴露给外部作用域,只通过受控接口访问。
用立即执行函数(IIFE)创建私有作用域
外层函数执行一次后立即销毁,但其内部变量因被返回的函数引用而持续存在——这就是闭包维持实例的原理。外部代码无法直接读写这个变量,连 console.log(instance) 都做不到,因为它根本不在全局或模块顶层作用域里。
- 声明一个 let instance 在 IIFE 内部,初始为 null 或 undefined
- 构造逻辑(如 new WebSocket、new ConfigManager)只在 getInstance 第一次调用时触发
- 返回的对象里不包含 instance 字段,只暴露方法,比如 getInstance、send、destroy
只暴露受控方法,切断直接访问路径
不是“不让别人改”,而是“别人根本看不见”。闭包不提供任何 getter 来取 instance 本身,也不允许通过属性遍历或调试器直接访问该变量。例如:
- ✅ 允许:Singleton.getInstance().getData()
- ❌ 禁止:Singleton.instance(不存在)、Singleton._instance(没定义)、console.dir(Singleton) 查不到原始引用
避免意外覆盖或重置
因为 instance 是闭包内纯私有变量,不会受外部赋值影响。即使有人写 Singleton.instance = null,也只是在 Singleton 对象上加了个新属性,对闭包里的那个 instance 毫无影响。
立即学习“Java免费学习笔记(深入)”;
- 没有原型链污染风险
- 不依赖 Symbol 或 WeakMap 做额外保护(虽可增强,但非必需)
- 模块热更新或多次 require 也不会重建——只要 IIFE 只执行一次,实例就唯一
对比其他方式更彻底的隐藏效果
ES 模块导出对象(export default {...})虽天然单例,但导出对象本身是可枚举、可修改的;class + static 属性则 instance 直接挂在类上,容易被误操作。而闭包方案从语言机制层面切断了所有常规访问通道,真正做到了“不可见即不可触”。


















