eventcenter类用map实现发布订阅模式,提供on/emit/off/once方法,支持*通配符和一次性订阅,需注意this绑定与内存泄漏。

用 Class 语法糖实现发布订阅模式,核心是封装一个事件中心类,内部维护事件名与回调函数列表的映射关系,提供 on(订阅)、emit(发布)、off(取消订阅)三个基础方法。写法简洁,逻辑清晰,适合轻量场景。
定义 EventCenter 类,支持基本增删查
用 Map 存储事件名到回调数组的映射,避免重复绑定时覆盖,也便于按事件名精准管理。
- 构造函数初始化一个空 Map:`this.events = new Map()`
-
on(type, callback):若事件名不存在,先设为空数组;再把回调推入对应数组 -
emit(type, ...args):取出该 type 对应的所有回调,依次执行,传入参数 -
off(type, callback?):不传 callback 则清空整个事件队列;传了则只移除匹配的回调(注意用===判断引用)
支持一次性订阅(once)和通配符事件(*)
增强实用性:一次触发后自动解绑;监听所有事件用于调试或日志。
-
once(type, callback):内部包装一层函数,执行后调用off(type, wrapper),再调用原 callback -
on('*', callback):特殊处理*,在emit时额外遍历所有*订阅者,并传入事件名和参数
注意 this 指向与内存泄漏风险
回调函数中的 this 默认丢失,建议使用者自行绑定,或在 on 时做兼容(如用箭头函数或显式 bind);长期订阅需记得 off,尤其在组件销毁、实例回收前清理。
- 推荐写法:
eventCenter.on('data', this.handleData.bind(this))或eventCenter.on('data', (...args) => this.handleData(...args)) - Vue/React 中常见做法:在
beforeUnmount或useEffect cleanup里统一调用off
完整可运行示例
以下是一个最小可用版本:
class EventCenter {
constructor() {
this.events = new Map();
}
on(type, callback) {
if (!this.events.has(type)) this.events.set(type, []);
this.events.get(type).push(callback);
}
emit(type, ...args) {
const cbs = this.events.get(type) || [];
cbs.forEach(cb => cb(...args));
// 触发 * 事件
const wilds = this.events.get('*') || [];
wilds.forEach(cb => cb(type, ...args));
}
off(type, callback) {
if (!callback) {
this.events.delete(type);
return;
}
const cbs = this.events.get(type);
if (cbs) {
const i = cbs.indexOf(callback);
if (i > -1) cbs.splice(i, 1);
}
}
once(type, callback) {
const wrapper = (...args) => {
callback(...args);
this.off(type, wrapper);
};
this.on(type, wrapper);
}
}











