原生js实现on emit

let obj = {};
const $on = (name,fn)=>{
    if(!obj[name]){
        obj[name] = [];
    }
    obj[name].push(fn);
}

const $emit = (name,val)=>{
    if(obj[name]){
        obj[name].map((fn)=>{
            fn(val);
        });
    }
}

const $off = (name,fn)=>{
    if(obj[name]){
        if(fn){
            let index = obj[name].indexOf(fn);
            if(index > -1){
                obj[name].splice(index,1);
            }           
        }else{
            obj[name].length = 0;
            //设长度为0比obj[name] = []更优,因为如果是空数组则又开辟了一个新空间,设长度为0则不必开辟新空间
        }  
    }
}

export default {
    $on,
    $emit,
    $off
}

转载于:https://www.cnblogs.com/aisiqi-love/p/10594461.html

<think>我们正在讨论如何使用原生JavaScript的Event对象来实现类似emit的功能(即事件触发)。根据引用[3]提到的事件中心(Event Emitter)机制,我们可以自己实现一个事件发射器。引用[2]也提到了Node.js的Event Emitter,但这里我们关注浏览器环境或原生JavaScript的实现。 在JavaScript中,我们可以使用自定义事件(CustomEvent)和事件目标(EventTarget)来实现事件发布-订阅模式。基本步骤包括: 1. 创建一个事件目标(通常是EventTarget的实例)。 2. 使用`addEventListener`订阅事件。 3. 使用`dispatchEvent`触发事件(即emit)。 下面我们详细说明如何实现: ### 步骤1:创建事件发射器类(使用EventTarget) 现代浏览器支持EventTarget,我们可以直接扩展它来创建自定义事件发射器。 ```javascript class EventEmitter extends EventTarget { // 触发事件(emitemit(eventName, detail) { const event = new CustomEvent(eventName, { detail }); this.dispatchEvent(event); } // 监听事件(onon(eventName, callback) { this.addEventListener(eventName, (event) => { callback(event.detail); }); } // 取消监听(off) off(eventName, callback) { this.removeEventListener(eventName, callback); } } ``` ### 步骤2:使用事件发射器 ```javascript // 创建事件发射器实例 const emitter = new EventEmitter(); // 监听事件 emitter.on('message', (data) => { console.log('收到消息:', data); }); // 触发事件 emitter.emit('message', { text: 'Hello, EventEmitter!' }); ``` ### 解释: - `emit`方法:创建一个`CustomEvent`事件,并将数据放在`detail`属性中,然后使用`dispatchEvent`触发。 - `on`方法:使用`addEventListener`监听事件,并在回调中取出`detail`数据。 - `off`方法:移除事件监听器。 ### 兼容性考虑: 如果需要在旧版浏览器中使用,可以检查`EventTarget`和`CustomEvent`的支持情况,或者使用传统的发布-订阅模式(自己管理事件监听器数组)。 ### 传统实现(不使用EventTarget): 如果不依赖浏览器内置的EventTarget,我们可以自己实现一个简单的事件发射器: ```javascript class EventEmitter { constructor() { this.events = {}; } // 监听事件 on(eventName, callback) { if (!this.events[eventName]) { this.events[eventName] = []; } this.events[eventName].push(callback); } // 触发事件 emit(eventName, ...args) { const callbacks = this.events[eventName]; if (callbacks) { callbacks.forEach(cb => cb(...args)); } } // 取消监听 off(eventName, callback) { const callbacks = this.events[eventName]; if (callbacks) { this.events[eventName] = callbacks.filter(cb => cb !== callback); } } } ``` 使用方式同上。 ### 总结: 使用原生JavaScript实现事件发射器(emit功能)有两种主要方式: 1. **利用浏览器内置的EventTarget和CustomEvent**:这种方式更符合DOM事件模型,但仅限于浏览器环境。 2. **传统发布-订阅模式**:自己管理事件和回调数组,这种方式更通用,可用于Node.js和浏览器。 ### 相关问题: 1. 事件发射器(Event Emitter)模式在前端开发中有哪些应用场景? 2. 如何避免事件监听造成的内存泄漏? 3. 原生JavaScript事件与自定义事件有何异同? </think>### 使用原生 JavaScript 实现 Event Emitter 功能 以下是使用原生 JavaScript 实现事件发射器(Event Emitter)功能的完整方法,基于发布-订阅模式[^3]。这种模式允许对象(发布者)触发事件,其他对象(订阅者)监听并响应这些事件。 #### 1. 核心实现代码 ```javascript class EventEmitter { constructor() { this.events = {}; // 存储事件和对应的回调函数 } // 订阅事件(监听) on(eventName, callback) { if (!this.events[eventName]) { this.events[eventName] = []; } this.events[eventName].push(callback); return this; // 支持链式调用 } // 触发事件(发射) emit(eventName, ...args) { const callbacks = this.events[eventName]; if (callbacks) { callbacks.forEach(cb => cb(...args)); } return this; // 支持链式调用 } // 取消订阅 off(eventName, callback) { const callbacks = this.events[eventName]; if (callbacks) { this.events[eventName] = callbacks.filter(cb => cb !== callback); } return this; // 支持链式调用 } // 一次性订阅 once(eventName, callback) { const onceWrapper = (...args) => { callback(...args); this.off(eventName, onceWrapper); }; this.on(eventName, onceWrapper); return this; } } ``` #### 2. 使用示例 ```javascript // 创建事件发射器实例 const emitter = new EventEmitter(); // 订阅事件 emitter.on('message', (text, sender) => { console.log(`收到消息: ${text},来自: ${sender}`); }); // 一次性订阅 emitter.once('welcome', (user) => { console.log(`欢迎新用户: ${user}`); }); // 触发事件(发射事件) emitter.emit('message', '你好,世界!', '系统'); emitter.emit('welcome', '小明'); emitter.emit('welcome', '小红'); // 不会触发,因为是一次性订阅 // 取消订阅示例 const handler = (data) => console.log('处理数据:', data); emitter.on('data', handler); emitter.off('data', handler); // 取消订阅 ``` #### 3. 核心功能说明 1. **事件订阅 (`on`)** 存储事件名称和对应的回调函数,支持多个回调函数绑定到同一事件[^3]。 2. **事件发射 (`emit`)** 触发指定事件,执行所有订阅的回调函数并传递参数[^1]。 3. **事件取消 (`off`)** 移除指定事件的特定回调函数,避免内存泄漏。 4. **一次性订阅 (`once`)** 通过包装函数实现只触发一次的事件监听[^3]。 #### 4. 高级用法:在 DOM 元素中使用 ```javascript // 创建自定义事件 const customEvent = new CustomEvent('custom', { detail: { message: '自定义数据' } }); // 监听自定义事件 document.addEventListener('custom', (e) => { console.log('收到自定义事件:', e.detail.message); }); // 触发自定义事件 document.dispatchEvent(customEvent); ``` #### 5. 使用场景 1. **组件通信**:在 UI 框架中实现组件间解耦通信 2. **插件系统**:允许插件监听核心系统的关键事件 3. **状态管理**:作为简单状态管理的基础(类似 Redux 的发布-订阅机制) 4. **异步操作**:事件驱动处理异步任务结果 ### 总结 通过实现 `EventEmitter` 类,我们创建了一个轻量级的事件系统,核心功能包括: - `on()` 用于事件订阅(监听) - `emit()` 用于事件触发(发射) - `off()` 用于取消订阅 - `once()` 用于一次性监听 这种模式遵循发布-订阅范式,实现了对象间的解耦通信[^3]。相比 Vue 的 `$emit` 和 `$on`,这个实现是框架无关的纯 JavaScript 解决方案[^1]。 ### 相关问题 1. 事件发射器模式与观察者模式有何区别? 2. 如何防止事件监听导致的内存泄漏问题? 3. 在 Vue/React 中如何集成自定义事件发射器? 4. Node.js 的 EventEmitter 与浏览器实现有何异同?[^2]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值