可用闭包封装事件总线,通过iife返回on/emit/off方法,内部用对象映射事件名与回调数组;on返回解绑函数确保精准移除,支持*通配符和once扩展。

可以用闭包封装事件监听和触发逻辑,避免全局变量污染,同时保证内部状态私有。
定义事件总线核心结构
用立即执行函数(IIFE)创建闭包,返回一个包含 on(订阅)、emit(发布)、off(取消订阅)方法的对象。内部用一个对象存储事件名到回调函数数组的映射。
- on(eventName, callback):将回调推入对应事件名的数组中
- emit(eventName, ...args):遍历该事件的所有回调并执行,传入参数
- off(eventName, callback):从数组中移除指定回调(可选:不传 callback 则清空整个事件)
处理回调移除的细节
由于函数引用需严格相等才能被 Array.prototype.indexOf 找到,建议在 on 中返回一个用于解绑的函数,或要求调用者保留原始回调引用。更稳妥的做法是让 on 返回一个 off 函数:
- 每次调用 on 时生成唯一标识(如闭包绑定),把回调存进数组,并返回一个闭包函数,它能精准删除本次注册的回调
- 这样用户无需手动管理引用,调用返回的函数即可解绑
支持通配符或一次触发
可在基础版本上轻量扩展:
- 支持
"*"监听所有事件:在 emit 时额外触发["*"]对应的回调 - 添加 once 方法:注册后自动在首次触发时调用 off,适合只响应一次的场景
实际使用示例
比如模块 A 发送登录成功事件,模块 B 订阅该事件更新 UI:
const bus = (function () {
const events = {};
return {
on(name, cb) {
if (!events[name]) events[name] = [];
events[name].push(cb);
return () => {
const i = events[name]?.indexOf(cb);
if (i > -1) events[name].splice(i, 1);
};
},
emit(name, ...args) {
(events[name] || []).forEach(cb => cb(...args));
(events["*"] || []).forEach(cb => cb(name, ...args));
},
off(name, cb) {
if (cb && events[name]) {
const i = events[name].indexOf(cb);
if (i > -1) events[name].splice(i, 1);
} else if (events[name]) {
events[name] = [];
}
}
};
})();
// 模块 B
const unsubscribe = bus.on("login.success", (user) => {
document.getElementById("welcome").textContent = `欢迎,${user.name}`;
});
// 模块 A
bus.emit("login.success", { name: "张三" });
// 后续可调用 unsubscribe() 取消监听
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











