闭包实现单例模式本质是利用函数作用域封装私有实例变量并通过内部函数复用,核心通过IIFE创建独立作用域缓存instance,首次调用初始化,后续返回同一引用,确保全局唯一且不可篡改。

闭包实现单例模式,本质是利用函数作用域封装一个私有实例变量,并通过返回的内部函数持续访问和复用它。这种方式不依赖 class 语法,兼容性好,逻辑清晰,是 JavaScript 中最经典、最稳妥的单例写法。
核心思路:用 IIFE 封装实例缓存
立即执行函数(IIFE)创建独立作用域,内部声明 instance 变量作为唯一实例容器;外部只能通过返回的函数访问它,无法绕过控制逻辑重新创建。
- 第一次调用时,检查 instance 是否为空,为空则初始化并赋值
- 后续调用直接返回已存在的 instance,保证引用完全相同
- 闭包让 instance 始终被保护,外部无法修改或重置(除非暴露销毁方法)
基础写法:带 getInstance 的对象接口
这是最推荐的结构,语义明确、调试友好、支持懒加载:
const Singleton = (function() {
let instance;
function createInstance() {
return {
data: 'I am the only one',
timestamp: Date.now()
};
}
return {
getInstance() {
if (!instance) {
instance = createInstance();
}
return instance;
}
};
})();
// 使用
const a = Singleton.getInstance();
const b = Singleton.getInstance();
console.log(a === b); // true
进阶写法:返回函数本身(更“透明”的调用方式)
如果希望调用看起来像普通函数(不用 .getInstance()),可直接返回一个闭包函数:
const singleton = (function() {
let instance;
return function(name) {
if (!instance) {
instance = { name, createdAt: Date.now() };
}
return instance;
};
})();
// 使用
const p1 = singleton('Alice');
const p2 = singleton('Bob'); // name 参数被忽略,仍返回同一实例
console.log(p1 === p2); // true
注意事项与常见误区
闭包单例看似简单,但几个细节容易出错:
- 别把 instance 放在全局:否则多个模块引入时可能互相覆盖,必须严格限定在闭包内
- 构造逻辑要真正只执行一次:避免在 createInstance 或构造过程中产生副作用(如重复绑定事件、发起请求)
- 不要试图用 new 破坏单例:闭包方案本身不阻止 new 调用,若需防御,应在内部做 instance 检查并返回已有实例(即“透明单例”)
-
需要销毁时,主动暴露 clear 或 destroy 方法:比如
destroy() { instance = null; },否则可能引发内存泄漏
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











