如何实现可全局调用的JavaScript自定义事件分发器
全局跨模块事件分发器实现方案
第一步:修复原有Dispatcher类的问题并实现单例导出
原有代码首先存在基础bug:constructor中未初始化events属性,直接调用方法会抛出undefined错误。我们利用ES模块的单例特性,导出初始化后的实例即可实现全局共享,无需挂载到window对象。
// dispatcher.js class Dispatcher{ constructor(){ // 初始化事件存储对象,用Object.create(null)避免原型链污染 this.events = Object.create(null) } addListener (event, callback) { if (typeof callback !== 'function') { console.error(`The listener callback must be a function, the given type is ${typeof callback}`); return false; } if (typeof event !== 'string') { console.error(`The event name must be a string, the given type is ${typeof event}`); return false; } if (this.events[event] === undefined) { this.events[event] = { listeners: [] } } this.events[event].listeners.push(callback); } removeListener(event, callback){ if(this.events[event] === undefined){ console.error(`This event: ${event} does not exist`); return false; } // 优化:直接比较函数引用,避免内容相同的不同函数被误删除 this.events[event].listeners = this.events[event].listeners.filter(listener => listener !== callback) } dispatch(event, details){ if(this.events[event] === undefined){ console.error(`This event: ${event} does not exist`); return false; } // 浅拷贝一份数组执行,避免回调里删除监听导致遍历异常 [...this.events[event].listeners].forEach((listener) => { listener(details); }) } } // 导出单例实例,所有模块导入的都是同一个实例,天然实现全局共享 export default new Dispatcher() // 如需创建独立的分发器实例,可额外导出类 export { Dispatcher }
第二步:跨模块使用示例
1. 在被导入的模块(如API2.js)中派发事件
// /js/API2.js import dispatcher from './dispatcher.js' export class API2 { fetchData() { // 业务逻辑执行完成后派发事件 dispatcher.dispatch('api-data-loaded', { data: {id: 1, content: 'test'} }) } }
2. 在main.js中监听事件
// main.js import dispatcher from './dispatcher.js' import { API2 } from '/js/API2.js' // 注册监听 dispatcher.addListener('api-data-loaded', (details) => { console.log('接收到API2派发的事件', details) }) // 触发API2逻辑,可正常收到事件通知 const api = new API2() api.fetchData()
原挂载window方案失效的常见原因
- 挂载的是Dispatcher类而非初始化后的实例,直接调用类的静态方法自然不存在
- 模块加载顺序错误,其他模块导入使用dispatcher时,还未执行挂载window的逻辑
- ES模块默认是隔离作用域,若你在模块内声明的dispatcher未显式挂到window上,其他模块无法访问
内容的提问来源于stack exchange,提问作者Nik Hendricks
相关产品推荐
相关产品推荐

