事件总线类通过on、emit、off实现注册监听、触发通知、取消订阅,使用对象存储事件名与回调数组映射,支持重复防重、错误隔离、内存清理及once一次性监听。

用 JavaScript 的 class 语法实现事件总线,核心是封装“注册监听”“触发通知”“取消订阅”三个能力,不依赖外部库,结构清晰、可复用性强。
定义基础类结构和事件存储容器
在构造函数中初始化一个对象(或 Map)用于存放事件名与回调函数数组的映射关系。用对象更直观,适合多数场景;Map 支持任意类型键,扩展性更好。
- 使用普通对象:this.events = {}
- 使用 Map:this.events = new Map()
- 每个事件名对应一个函数数组,便于支持多个监听器同时响应
实现 on 方法:注册事件监听器
接收事件名和回调函数,将函数推入对应事件名的数组中。若该事件名尚无记录,则先初始化空数组。
- 确保重复添加同一函数不会导致多次执行(可选增强)
- 返回一个取消订阅函数,方便链式调用或手动清理:return () => this.off(type, fn)
实现 emit 方法:派发事件消息
根据事件名查找已注册的回调数组,依次执行所有监听函数,并传入参数。建议加 try-catch 防止单个监听器报错阻断后续执行。
- 参数可展开传递:fn.apply(this, args) 或 fn(...args)
- 若需兼容旧浏览器,避免使用展开运算符时可用 Array.prototype.forEach + Function.prototype.apply
- 不匹配事件名时静默处理,不报错
实现 off 方法:移除指定监听器
从对应事件名的数组中删除指定回调函数。注意要严格比对引用,不能只比对函数体内容。
- 使用 indexOf + splice 定位并删除
- 若未传回调函数,可支持清空整个事件的所有监听器
- 删除后可判断数组是否为空,为空则从 events 中删掉该 key,节省内存
补充 once 方法(可选):一次性监听
本质是在 on 注册一个包装函数,该函数执行后立即调用 off 清除自己。
- 避免闭包中 this 指向混乱,推荐用箭头函数或显式绑定
- 包装函数内部先调用原始回调,再执行 off,保证逻辑顺序


















