闭包可封装 observers 数组实现私有状态,仅暴露 subscribe/unsubscribe/notify 接口,防止外部直接访问或修改;进阶可用 Map+Set 按事件名分组并去重,所有数据结构均不泄漏。

闭包可以自然地封装通知列表(如回调函数数组),使其不被外部直接访问或修改,同时暴露安全的注册、移除和触发接口——这是轻量级观察者模式中隐藏内部状态的核心手段。
用闭包包裹 observers 数组
将存储监听器的数组定义在闭包作用域内,外部无法直接读取或清空它,只能通过返回的对象方法操作:
function createObserver() {
const observers = []; // ✅ 外部不可见、不可访问
return {
subscribe(fn) {
if (typeof fn === 'function') {
observers.push(fn);
}
},
unsubscribe(fn) {
const index = observers.indexOf(fn);
if (index > -1) observers.splice(index, 1);
},
notify(data) {
observers.forEach(fn => fn(data));
}
};
}
// 使用
const bus = createObserver();
bus.subscribe(console.log);
bus.notify('hello'); // ✅ 正常执行
console.log(bus.observers); // ❌ undefined —— 完全隐藏
支持唯一订阅与事件名细分(进阶封装)
仍用闭包维护一个私有 map 结构,按事件类型分组管理回调,同时避免重复添加同一函数:
说明:内部用 Map 存储 event → Set 映射,Set 保证函数去重;所有数据结构均不暴露。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
立即学习“Java免费学习笔记(深入)”;
function createEventBus() {
const events = new Map(); // ✅ 私有,外部不可触达
return {
on(event, fn) {
if (!events.has(event)) {
events.set(event, new Set());
}
events.get(event).add(fn);
},
off(event, fn) {
if (events.has(event)) {
events.get(event).delete(fn);
}
},
emit(event, data) {
if (events.has(event)) {
events.get(event).forEach(fn => fn(data));
}
}
};
}
防止外部篡改闭包变量的注意事项
闭包本身不能阻止“引用泄漏”,需注意以下几点:
- 不要返回内部数组或 Set 的引用(例如
return observers或return events.get(event)),否则外部可直接修改 - 如果需要遍历快照,应返回拷贝:
return [...observers](但通常不建议暴露) - 避免在返回的方法中暴露原始数据结构,所有交互必须走受控接口
为什么不用 class + #private?
虽然 ES2022 支持私有字段(#observers),但闭包方案更轻量、兼容性更好(IE 都能跑),且逻辑边界更清晰——没有类实例状态干扰,纯函数式封装,适合工具型观察者(如全局事件总线、配置变更通知等)。

















