javascript中闭包可实现单例模式,通过iife封装私有instance变量,首次调用创建实例并缓存,后续调用直接返回该实例,确保全局唯一且避免污染全局作用域。

在 JavaScript 中,闭包可以用来实现单例模式,核心思路是利用闭包保存一个私有实例变量,确保全局只创建一次对象,并通过返回的函数提供对该实例的唯一访问入口。
用闭包封装私有实例
闭包能维持对外部作用域中变量的引用,因此可以把实例缓存在立即执行函数(IIFE)内部,避免污染全局,也防止外部直接修改或重复创建。
- 定义一个 IIFE,内部声明一个私有变量 instance
- 在 IIFE 内部定义构造逻辑(如一个类或普通对象)
- 返回一个函数,该函数检查 instance 是否已存在;不存在则新建,存在则直接返回
基础实现示例
以下是一个简洁、可复用的单例工厂函数:
const Singleton = (function() {
let instance = null;
function createInstance() {
// 这里可以是任意初始化逻辑,比如 new SomeClass()
return {
name: 'Singleton Instance',
getId: () => Math.random().toString(36).substr(2, 9)
};
}
return function() {
if (!instance) {
instance = createInstance();
}
return instance;
};
})();
// 使用
const a = Singleton();
const b = Singleton();
console.log(a === b); // true
支持传参的增强版(惰性初始化 + 参数透传)
如果需要根据首次调用时的参数初始化实例(例如传入配置),可在第一次调用时捕获参数并缓存,后续忽略参数:
- 把 createInstance 改为接受参数
- 使用闭包变量标记是否已初始化,以及缓存首次参数(如需)
- 注意:若参数影响实例行为,应确保多次调用时参数一致,或抛出提示
const ConfigurableSingleton = (function() {
let instance = null;
let initArgs = null;
function createInstance(config) {
return {
config: { ...config },
status: 'active'
};
}
return function(config) {
if (!instance) {
instance = createInstance(config);
initArgs = config;
}
return instance;
};
})();
注意事项与适用场景
闭包单例适合轻量、无复杂生命周期管理的对象(如工具类、配置管理器、日志器)。它不依赖 ES6 类语法,兼容性好,但要注意:
- 无法通过 new 调用,只能作为函数调用
- 不支持继承或 instanceof 判断(返回的是普通对象);如需类型识别,可用 Symbol.toStringTag 或自定义 constructor 属性
- 测试时难以重置实例(因闭包内变量不可访问),可加一个私有 reset 方法用于开发调试(生产环境移除)











