闭包可实现单例模式:通过IIFE封装实例变量与构造逻辑,对外仅暴露一个首次调用初始化、后续返回同一引用的工厂函数,支持延迟初始化及参数校验,适用于配置类等场景。

闭包可以用来创建一个私有作用域,保存唯一实例并控制其访问,从而实现单例模式。核心思路是:利用闭包封装实例变量,对外只暴露一个获取实例的函数,确保全局仅存在一个对象实例。
用闭包封装实例和构造逻辑
把构造函数和实例变量放在立即执行函数(IIFE)内部,避免外部直接访问或重复创建。返回一个函数,首次调用时初始化实例,之后始终返回同一引用。
- 实例变量声明在闭包内,外部无法修改或重置
- 构造逻辑(如 new SomeClass())只执行一次
- 返回的工厂函数可带参数,但需注意:若参数影响实例状态,应确保参数一致或做校验
支持延迟初始化(Lazy Initialization)
实例不是在定义时创建,而是在第一次调用 getInstance 时才生成,节省资源,尤其适用于开销较大的对象。
- 适合配置类、日志器、数据库连接池等场景
- 如果构造函数依赖异步操作(如 fetch 配置),可在闭包中加 Promise 缓存,避免多次触发
保证线程安全?JavaScript 中通常无需担心
单线程环境下,闭包天然避免并发创建问题;但在 Node.js 多实例部署或 Web Worker 场景中,“单例”仅限当前 JS 执行上下文。跨进程/页面不共享。
- 浏览器中每个 iframe 或 tab 是独立执行环境,各自有独立单例
- Node.js 中模块缓存机制(require.cache)让同一模块的闭包单例在同进程内真正唯一
- 若需跨 worker 共享,需借助 SharedArrayBuffer 或服务端协调,闭包本身无法解决
简单可复用的模板写法
以下是一个通用结构,传入构造函数即可生成单例工厂:
const createSingleton = (constructor) => {
let instance;
return (...args) => {
if (!instance) {
instance = new constructor(...args);
}
return instance;
};
};
// 使用
const Logger = createSingleton(class {
constructor(name) {
this.name = name;
this.count = 0;
}
log(msg) {
console.log(`${this.name}: ${msg} #${++this.count}`);
}
});
const a = Logger('main');
const b = Logger('main');
console.log(a === b); // true

















