JavaScript中class实现发布订阅模式的核心是用Map维护事件名到回调数组的映射,提供on(订阅)、emit(发布)、off(取消订阅)方法,支持去重、错误隔离与once扩展。

JavaScript 中用 class 实现发布订阅模式,核心是维护一个事件名到回调函数列表的映射,提供 on(订阅)、emit(发布)、off(取消订阅)三个基本方法。
基础结构:用 Map 存储事件监听器
推荐用 Map 或普通对象管理事件名与回调数组的映射。用 Map 更安全(避免原型污染、支持任意类型键),且语义清晰:
- 每个事件名(字符串或 Symbol)对应一个回调函数数组
- 订阅时把回调推入对应数组;发布时遍历并执行全部回调
- 取消订阅时从数组中移除指定回调(注意区分匿名函数无法精确取消)
完整可运行的 class 实现
以下是一个轻量、健壮的实现,支持重复订阅去重、一次性事件(可选扩展)、错误隔离:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
class EventEmitter {
constructor() {
this.events = new Map();
}
// 订阅事件
on(type, callback) {
if (typeof callback !== 'function') {
throw new TypeError('Callback must be a function');
}
if (!this.events.has(type)) {
this.events.set(type, []);
}
const listeners = this.events.get(type);
// 避免重复添加同一函数
if (!listeners.includes(callback)) {
listeners.push(callback);
}
}
// 发布事件
emit(type, ...args) {
const listeners = this.events.get(type);
if (!listeners || listeners.length === 0) return;
// 浅拷贝防止执行过程中被修改(如 off 或 on)
[...listeners].forEach(callback => {
try {
callback(...args);
} catch (err) {
console.error(`Event ${type} handler threw error:`, err);
}
});
}
// 取消订阅
off(type, callback) {
const listeners = this.events.get(type);
if (!listeners) return;
if (callback) {
const index = listeners.indexOf(callback);
if (index > -1) {
listeners.splice(index, 1);
}
} else {
// 不传 callback → 清空该事件所有监听器
listeners.length = 0;
}
}
// (可选)只执行一次的订阅
once(type, callback) {
const onceWrapper = (...args) => {
callback(...args);
this.off(type, onceWrapper);
};
this.on(type, onceWrapper);
}
}
使用示例
验证功能是否正常:
立即学习“Java免费学习笔记(深入)”;
const ee = new EventEmitter();
ee.on('data', (msg) => console.log('Received:', msg));
ee.on('error', (err) => console.error('Error:', err));
ee.emit('data', 'hello'); // → "Received: hello"
ee.emit('error', 'network'); // → "Error: network"
// 取消特定监听
ee.off('data', (msg) => console.log('Received:', msg)); // 注意:此匿名函数 ≠ 上面那个,实际不生效
// 正确做法:复用同一函数引用
const handler = (msg) => console.log('Handled:', msg);
ee.on('log', handler);
ee.off('log', handler); // ✅ 成功移除
注意事项和优化点
-
函数引用必须一致:
off依赖严格相等(===),所以不要用匿名函数做需取消的订阅 -
异步事件安全:当前 emit 是同步执行;如需异步(例如 Promise.all 并行),可封装
emitAsync -
内存泄漏防范:长期运行的应用记得在合适时机调用
off,或用 WeakMap 管理对象级事件(进阶) -
支持通配符或命名空间:可在
on/emit中加入简单匹配逻辑(如'user.*'),但会增加复杂度,按需引入
不复杂但容易忽略细节,掌握这个 class 模板,就能在项目中灵活构建松耦合的通信机制。

















