事件总线本质是轻量级发布-订阅模式,通过对象/Map存储事件名与回调数组映射;支持on/emit/off操作,含去重、this绑定、once、错误隔离及通配符等扩展能力。

JavaScript 中事件总线(Event Bus)本质是一个轻量级的发布-订阅模式实现,函数作为回调被动态注册(订阅)和触发(发布),核心在于用对象或 Map 存储事件名与回调函数列表的映射关系。
订阅:用数组存回调,支持重复/去重与上下文绑定
每次调用 on(event, callback) 时,把回调推入对应事件名的函数数组。可扩展支持:
- 自动去重:检查回调是否已存在(需用
===或 WeakMap 记录引用) - 绑定 this:允许传入 context,内部用
callback.bind(context)存储 - 一次性订阅:提供
once(event, callback),触发后自动移除
示例:
bus.on('user:login', function(data) { console.log('欢迎', data.name); });
发布:遍历执行,支持参数透传与错误隔离
emit(event, ...args) 查找该事件的所有回调并依次调用。关键细节:
立即学习“Java免费学习笔记(深入)”;
- 用
try...catch包裹每个回调,避免一个报错中断其余执行 - 参数直接展开传递:
cb.apply(thisArg, args)或cb(...args) - 若事件无订阅者,静默忽略,不抛错
示例:
bus.emit('user:login', { name: 'Alice' }); // 触发上面的回调
取消订阅:精准移除,支持批量与通配符(可选)
off(event, callback) 是必须功能:
- 只传 event:清空该事件所有回调
- 传 event 和 callback:仅移除指定函数(需比对引用,不能传匿名函数)
- 进阶可支持通配符如
user:*,需用正则或前缀匹配遍历键名
注意:若订阅时用了 bind(),取消时必须传入绑定后的函数引用,否则无法匹配。
实战建议:避免内存泄漏与作用域陷阱
真实项目中容易出问题的地方:
- 组件销毁时忘记
off()→ 回调持续持有组件实例引用 → 内存泄漏 - 箭头函数订阅 → 每次都是新函数 →
off()失效 → 应提前定义变量再传入 - 跨模块通信时事件名硬编码 → 推荐用常量对象统一管理,如
EVENT.USER_LOGIN
简单可靠的 bus 实现只需 20 行左右,不必引入第三方库,尤其适合 Vue 2 或小型应用。


















