闭包在发布订阅模式中主要用于隔离和持久化订阅者队列,避免全局污染并确保各事件通道拥有独立私有的监听函数集合。

闭包在发布订阅模式中主要用于**隔离和持久化订阅者队列(callbacks 数组)**,避免全局污染,同时让每个事件通道拥有独立、私有的监听函数集合。
闭包封装独立的事件队列
通过立即执行函数或工厂函数创建闭包,把 callbacks 数组定义在闭包作用域内,外部无法直接访问,只能通过返回的 on(订阅)、emit(发布)、off(取消订阅)方法操作:
function createEventChannel() {
const callbacks = []; // ✅ 私有队列,被闭包捕获
return {
on(fn) {
callbacks.push(fn);
},
emit(data) {
callbacks.forEach(fn => fn(data));
},
off(fn) {
const index = callbacks.indexOf(fn);
if (index > -1) callbacks.splice(index, 1);
}
};
}
// 每个 channel 都有自己独立的 callbacks
const userLogin = createEventChannel();
const paymentSuccess = createEventChannel();
支持多事件类型(带事件名的闭包方案)
更常见的发布订阅需支持多种事件名(如 'login'、'logout')。此时用一个对象管理各事件名对应的回调队列,仍靠闭包保护该对象:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
function createPubSub() {
const events = {}; // ✅ 所有事件队列都藏在这里
return {
on(type, fn) {
if (!events[type]) events[type] = [];
events[type].push(fn);
},
emit(type, data) {
(events[type] || []).forEach(fn => fn(data));
},
off(type, fn) {
if (events[type]) {
const index = events[type].indexOf(fn);
if (index > -1) events[type].splice(index, 1);
}
}
};
}
const bus = createPubSub();
bus.on('user:update', console.log);
bus.emit('user:update', { id: 123 });
避免内存泄漏的关键细节
闭包让队列常驻内存,若不手动 off,回调函数和其上下文会一直被引用。实践中要注意:
- 组件销毁(如 React
useEffect清理、VuebeforeUnmount)时必须调用off - 避免传入匿名函数订阅,否则无法精确取消:
bus.on('data', () => {...})→ 后续无法off - 可改用 WeakMap 存储 callback 引用(高级场景),但主流实现仍依赖显式取消
与 class 实现的对比说明
用 class 写也能封装队列(this.callbacks),但闭包方案天然无实例属性暴露风险,且更轻量——不需要 new,函数即服务。两者本质都是“数据私有化”,闭包是 JavaScript 原生、函数式的表达方式。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










