news 2026/7/2 7:03:20

js自定义Emitter,实现1对多的事件派发处理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
js自定义Emitter,实现1对多的事件派发处理

增加监听on、派发事件emit、移除指定监听off、移除所有监听removeAllListenners

<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> </head> <body> <script> class SimpleEventEmitter { /** * 存储事件名到监听器列表的映射 * @private * @type {Map<string, Function[]>} */ _events = new Map(); /** * 注册⼀个事件监听器。 * @param {string} eventName 事件的名称。 * @param {Function} listener 事件发⽣时应调⽤的函数。 * @returns {this} 返回 EventEmitter 实例,⽅便链式调⽤。 */ on(eventName, listener) { if (typeof listener !== 'function') { throw new TypeError('Listener must be a function'); } if (!this._events.has(eventName)) { this._events.set(eventName, []); } // 避免重复添加相同的监听器,简化版可以不考虑,但实际通常会考虑 // if (!this._events.get(eventName).includes(listener)) { this._events.get(eventName).push(listener); // } return this; } /** * 触发⼀个事件,调⽤所有注册到该事件的监听器。 * @param {string} eventName 要触发的事件的名称。 * @param {...any} args 传递给监听器的参数。 * @returns {boolean} 如果事件有监听器被调⽤,则返回 true;否则返回 false。 */ emit(eventName, ...args) { if (!this._events.has(eventName)) { return false; // 没有注册该事件的监听器 } const listeners = this._events.get(eventName).slice(); // 创建副本 以防⽌在遍历过程中修改数组 for (const listener of listeners) { try { // 在这⾥,监听器中的 `this` 通常会丢失,如果是类⽅法,需要绑定或使⽤箭头函数 // `listener.call(this, ...args);` 如果需要绑定触发者的上下⽂ listener(...args); } catch (error) { // 实际 EventEmitter 通常会有⼀个 'error' 事件来处理监听器中的错误 console.error(`Error in event listener for "${eventName}":`, error); } } return listeners.length > 0; } /** * 移除指定的事件监听器。 37. 实现⼀个简化版 EventEmitter 2 / 5 * @param {string} eventName 事件的名称。 * @param {Function} listener 要移除的监听器函数。 * @returns {this} 返回 EventEmitter 实例,⽅便链式调⽤。 */ off(eventName, listener) { if (typeof listener !== 'function') { throw new TypeError('Listener must be a function'); } if (!this._events.has(eventName)) { return this; // 没有注册该事件的监听器 } const listeners = this._events.get(eventName); const index = listeners.indexOf(listener); if (index !== -1) { listeners.splice(index, 1); } // 如果该事件没有剩余的监听器,可以考虑从 Map 中移除该键,以节省内存 if (listeners.length === 0) { this._events.delete(eventName); } return this; } /** * 移除所有事件的所有监听器,或指定事件的所有监听器。 * @param {string} [eventName] 如果指定,则只移除该事件的监听器;否则移除所 有事件的监听器。 * @returns {this} 返回 EventEmitter 实例,⽅便链式调⽤。 */ removeAllListeners(eventName) { if (eventName) { this._events.delete(eventName); } else { this._events.clear(); } return this; } } // --- 示例⽤法 --- const myEmitter = new SimpleEventEmitter(); function handler1(arg1, arg2) { console.log('Handler 1 received:', arg1, arg2); } // 4. 关键注意事项 (Key Considerations) function handler2(arg) { console.log('Handler 2 received:', arg); } myEmitter.on('data', handler1); myEmitter.on('data', handler2); myEmitter.on('status', (status) => { console.log('Status changed:', status); }); console.log('--- Emitting "data" ---'); myEmitter.emit('data', 'Hello', 'World'); // Output: Handler 1 received: Hello World, Handler 2 received: Hello World console.log('--- Emitting "status" ---'); myEmitter.emit('status', 'active'); // Output: Status changed: active console.log('--- Emitting non-existent event ---'); myEmitter.emit('nonexistent'); // Output: false (returned by emit) console.log('--- Removing handler2 from "data" ---'); myEmitter.off('data', handler2); console.log('--- Emitting "data" again ---'); myEmitter.emit('data', 'Goodbye'); // Output: Handler 1 received: Goodbye console.log('--- Removing all listeners for "data" ---'); myEmitter.removeAllListeners('data'); console.log('--- Emitting "data" one last time ---'); myEmitter.emit('data', 'Final'); // No output </script> </body> </html>
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 7:02:05

多链路聚合:无人机电力巡检的“超视距生命线”

多链路聚合&#xff1a;无人机电力巡检的“超视距生命线”传统电力巡检中&#xff0c;无人机常面临山区信号盲区、变电站强电磁干扰、高空基站切换卡顿等难题&#xff0c;导致图传中断、“盲飞”风险高&#xff0c;4K高清及红外数据无法实时回传。多链路聚合设备通过融合多运营…

作者头像 李华
网站建设 2026/7/2 7:00:33

深度解析:Cursor编辑器系统配置优化与开发环境稳定化架构设计

深度解析&#xff1a;Cursor编辑器系统配置优化与开发环境稳定化架构设计 【免费下载链接】go-cursor-help 解决Cursor在免费订阅期间出现以下提示的问题: Your request has been blocked as our system has detected suspicious activity / Youve reached your trial request …

作者头像 李华
网站建设 2026/7/2 7:00:17

计算机Java毕设实战-基于 SpringBoot 的应急储备物资仓储管理系统的设计与实现【完整源码+LW+部署说明+演示视频,全bao一条龙等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/7/2 6:59:51

实现知识无缝迁移:Obsidian Importer多平台笔记导入解决方案

实现知识无缝迁移&#xff1a;Obsidian Importer多平台笔记导入解决方案 【免费下载链接】obsidian-importer Convert your data to Markdown files you can use in Obsidian. Works with Apple Notes, OneNote, Evernote, Notion, Google Keep, and many other formats. 项目…

作者头像 李华
网站建设 2026/7/2 6:59:25

原生 H5 与伪 H5 支付区别介绍

H5 支付是适配移动端浏览器的线上支付方式&#xff0c;用户在手机外置浏览器下单时&#xff0c;可直接唤起微信、支付宝完成付款。H5 支付主要分为原生 H5与伪 H5两类&#xff1a;原生 H5 支付&#xff1a;直接拉起微信、支付宝客户端跳转支付&#xff0c;也就是常说的唤起支付…

作者头像 李华
网站建设 2026/7/2 6:57:31

MeEdu开源教育系统:如何构建多云协同的视频点播架构

MeEdu开源教育系统&#xff1a;如何构建多云协同的视频点播架构 【免费下载链接】meedu MeEdu 是一款面向个人、中小机构的在线网校、知识付费、线上培训解决方案。 项目地址: https://gitcode.com/gh_mirrors/me/meedu 在线教育机构在技术架构上面临着三重困境&#xf…

作者头像 李华