JavaScript单例模式推荐通过静态工厂方法getInstance()管理唯一实例:类内设static instance=null,getInstance中检查并创建,禁止直接new;支持带参初始化,但仅限首次调用。

在 JavaScript 中,单例模式可以通过 class 的 static 属性保存唯一实例,核心思路是:用一个静态属性(如 instance)缓存已创建的实例,构造函数中判断该属性是否存在,不存在才新建并赋值,否则直接返回已有实例。
用 static instance 缓存并控制实例创建
在类内部定义一个 static instance = null,并在构造函数中检查它。若已存在,抛出错误或直接返回(但注意:new 必须返回对象,不能“跳过”构造;所以更稳妥的做法是把实例获取逻辑移到静态方法里)。
推荐写法是——**不依赖构造函数做控制,而是通过静态工厂方法(如 getInstance())统一管理**:
- 构造函数保持私有语义(可加注释或用 Symbol 模拟私有,但 JS 无真正私有构造)
-
static getInstance()检查MySingleton.instance,不存在则new MySingleton()并赋值 - 所有外部调用都走
MySingleton.getInstance(),确保唯一性
完整可运行示例
以下是一个简洁、符合 ES6+ 规范的单例 Class 实现:
class Logger {
static instance = null;
constructor() {
if (Logger.instance) {
throw new Error('Logger is a singleton. Use Logger.getInstance() instead.');
}
this.logs = [];
}
static getInstance() {
if (!Logger.instance) {
Logger.instance = new Logger();
}
return Logger.instance;
}
log(message) {
this.logs.push(`[${new Date().toISOString()}] ${message}`);
}
}
// 使用方式:
const a = Logger.getInstance();
const b = Logger.getInstance();
console.log(a === b); // true
a.log('Hello');
b.log('World');
console.log(a.logs); // 两条日志都存在
注意事项与常见误区
直接在 constructor 内部 return 另一个对象虽可行,但会破坏 instanceof 判断,且易被绕过(比如反射或子类继承)。因此不推荐。
- 避免在构造函数中
return静态实例(会导致new X() instanceof X === false) - 不要暴露
new调用入口,文档和代码逻辑应引导用户只用getInstance() - 如果需要延迟初始化(比如依赖异步资源),可在
getInstance()中加入 Promise 缓存逻辑 - 多线程/Worker 场景下,static 实例仅在当前 JavaScript 执行上下文有效(每个 Worker 独立)
进阶:支持参数的单例(带初始化配置)
若单例需首次创建时传参(如 API 地址、环境配置),可扩展 getInstance(options),并用 static options 或 WeakMap 记录是否已初始化:
class ConfigurableService {
static instance = null;
static initOptions = null;
constructor(options) {
if (!options || typeof options !== 'object') {
throw new Error('Options required for first initialization');
}
this.options = options;
}
static getInstance(options = null) {
if (ConfigurableService.instance) {
return ConfigurableService.instance;
}
if (!options) {
throw new Error('First call to getInstance must provide options');
}
ConfigurableService.instance = new ConfigurableService(options);
return ConfigurableService.instance;
}
}
这样既保证了单例本质,又支持一次性的初始化配置。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











