EventBus类实现事件总线,用Map存储事件名与监听函数数组,支持on/emit/off/clear方法,确保函数引用一致方可正确取消订阅。

JavaScript 中用 class 实现事件总线(Event Bus),核心是封装一个可订阅、发布、取消订阅的轻量级对象,不依赖外部库,也不绑定 DOM 元素。下面是一个简洁、健壮、可直接使用的实现。
基础结构:用 Map 存储事件监听器
使用 Map 以事件名(字符串)为键,值为监听函数数组,支持同一事件注册多个回调,且避免重复添加(可选去重逻辑)。
关键点:
- 每个事件名对应一个函数列表,便于批量触发
- 用
WeakMap或闭包隔离实例状态,避免全局污染 - 支持传参,触发时把参数原样透传给所有监听器
完整可运行的 EventBus class 实现
以下代码兼容现代浏览器和 Node.js(ES6+ 环境):
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
class EventBus {
constructor() {
this.events = new Map();
}
// 订阅事件
on(event, callback) {
if (typeof callback !== 'function') {
throw new Error('Callback must be a function');
}
if (!this.events.has(event)) {
this.events.set(event, []);
}
const listeners = this.events.get(event);
if (!listeners.includes(callback)) {
listeners.push(callback);
}
}
// 发布事件
emit(event, ...args) {
const listeners = this.events.get(event);
if (listeners && listeners.length > 0) {
// 浅拷贝防止执行中被修改影响遍历
[...listeners].forEach(cb => cb(...args));
}
}
// 取消单个监听
off(event, callback) {
const listeners = this.events.get(event);
if (listeners) {
const index = listeners.indexOf(callback);
if (index > -1) {
listeners.splice(index, 1);
}
// 清空后自动删除 key,节省内存
if (listeners.length === 0) {
this.events.delete(event);
}
}
}
// 清空某事件所有监听,或全部事件(不传 event)
clear(event) {
if (event === undefined) {
this.events.clear();
} else {
this.events.delete(event);
}
}
}
使用示例:跨组件通信场景
比如 Vue 或 React 中子组件发消息、父组件或其他模块响应:
// 创建实例(通常作为全局或模块级单例)
const bus = new EventBus();
// 组件 A:发送登录成功事件
function login() {
// ... 登录逻辑
bus.emit('user:login', { id: 123, name: 'Alice' });
}
// 组件 B:监听并处理
bus.on('user:login', (user) => {
console.log('欢迎回来:', user.name);
});
// 组件 C:只监听一次(手动 off 实现 once)
const onceHandler = (user) => {
console.log('首次登录提示:', user.name);
bus.off('user:login', onceHandler);
};
bus.on('user:login', onceHandler);
进阶建议:增强可靠性与调试性
生产环境可补充以下能力:
-
once 方法:内部调用
on+ 自动off,避免手动清理 - listenerCount:返回某事件当前监听数,方便调试
-
调试开关:加
debug: true选项,控制台打印 emit/on/off 日志 -
异步安全:若需保证监听器按注册顺序执行,保持
push和forEach的自然顺序即可(已满足)
不复杂但容易忽略:确保 off 传入的是同一个函数引用——箭头函数或内联函数每次都是新引用,无法正确移除。

















