闭包实现单例的关键在于IIFE封装私有instance变量并仅通过getInstance方法控制访问;支持懒加载、灵活构造逻辑及多种封装方式,但需避免暴露变量或重复导入;ES模块导出天然单例更简洁可靠。

闭包能保证单例唯一,关键在于把实例变量藏在函数作用域里,外部既不能直接读写,也无法绕过控制逻辑新建实例。只要 getInstance 是唯一出口,就天然锁死了多实例可能。
用 IIFE 封装私有实例变量
立即执行函数(IIFE)创建独立作用域,里面声明的 instance 对外部完全不可见,只能通过返回的对象方法访问:
- 变量
instance初始为null或undefined -
getInstance每次调用都先检查instance是否已存在 - 不存在才调用构造逻辑生成对象,并赋值给
instance - 后续调用直接返回缓存的引用,不重复创建
构造逻辑可灵活封装
创建实例的过程可以是简单对象字面量,也可以是 new 构造函数,甚至带参数的工厂函数:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 用普通函数封装:适合轻量、无状态的单例(如工具类)
- 用 class 配合闭包:在
createInstance里new MyClass(),保持面向对象结构 - 支持懒加载:实例只在首次
getInstance()时初始化,节省启动资源
避免常见误操作
即使用了闭包,仍需注意几个容易破坏单例的行为:
立即学习“Java免费学习笔记(深入)”;
- 不要导出或暴露
instance变量本身,否则别人可直接赋值覆盖 - 不要在
getInstance外部重新赋值,比如Singleton.instance = {} - 如果模块被多次 import(非严格模块系统下),确保 IIFE 只执行一次——现代 ES 模块天然解决这点
- 避免在构造函数里做副作用操作(如 DOM 插入),除非明确只需一次且时机可控
模块级单例更自然
ES 模块本身就是单例:一个文件导出一个对象,无论被 import 多少次,都共享同一份内存实例:
- 直接
export const logger = { log() { ... } }就是天然单例 - 配合默认导出
export default new ConfigManager()同样有效 - 这种方式比手写闭包更简洁、无歧义,也更容易测试和 tree-shaking

















