基于按需延迟加载的单例在class内通过私有字段#instance和只读getter实现:首次访问instance时初始化并缓存,之后始终返回同一实例;推荐用#instance = null初始化,配合存在性判断确保惰性构造与唯一性。

在 class 内部实现基于按需延迟加载的单例,核心是用存取器(getter)封装实例创建逻辑,确保首次访问时才初始化,之后始终返回同一实例。关键在于:实例变量需私有、不可被外部修改,且 getter 内部需做存在性判断和惰性构造。
声明私有静态实例字段
使用 #instance 语法(ES2022 私有字段)或弱映射(WeakMap)保护实例不被外部篡改。推荐私有字段,简洁直观:
- 用 #instance = null 初始化为 null,明确表示尚未创建
- 避免直接暴露 instance 属性,防止外部赋值破坏单例契约
- 若需兼容旧环境,可用 WeakMap + this 作键来模拟私有存储
定义只读的 getter 存取器
在类中定义 get instance(),内部检查私有字段是否已存在,不存在则新建并缓存:
- 每次调用 MyClass.instance 都触发该 getter
- 判断 this.#instance === null(或 undefined),成立则执行 this.#instance = new MyClass()
- 注意:此处 new MyClass() 是创建自身实例,适用于“类自己管理单例”场景;若构造需参数,应改用工厂函数或提前注入依赖
确保构造逻辑不重复执行
单例的“延迟”和“唯一”依赖 getter 的幂等性。需规避常见陷阱:
- 不要在 getter 中调用可能抛错的异步操作(如 await fetch),否则每次访问都重试——延迟加载应是同步、确定性的
- 若初始化含副作用(如注册监听、连接资源),确保这些操作只运行一次,且失败时合理处理(例如缓存错误或重试策略)
- 避免在 getter 中返回新对象字面量(如 {}),这会破坏单例语义
配合私有构造函数增强约束(可选)
进一步防止误用 new 实例化,可用私有符号或运行时校验:
- 定义私有静态标记 #constructing = false,在 constructor 中设为 true,getter 创建时临时置为 true,创建后恢复
- constructor 内检查该标记,非 true 时抛错:“Singleton must be accessed via .instance”
- 更轻量方式:在 constructor 第一行加 if (new.target !== Singleton) throw new Error(...),限制仅允许通过 new 调用(但无法阻止 new 的滥用,需结合 getter 使用)











