Bootstrap

实现一个观察者模式(on、off、once)

在这里插入图片描述

🤍 前端开发工程师、技术日更博主、已过CET6
🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1
🕠 牛客高级专题作者、打造专栏《前端面试必备》《2024面试高频手撕题》
🍚 蓝桥云课签约作者、上架课程《Vue.js 和 Egg.js 开发企业级健康管理项目》《带你从入门到实战全面掌握 uni-app》
💬 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站

on(用于订阅事件)

off(用于取消订阅事件)

once(用于订阅只执行一次的事件)

以下是使用JavaScript实现一个简单的观察者模式,包含on(用于订阅事件)、off(用于取消订阅事件)、once(用于订阅只执行一次的事件)方法的示例代码,观察者模式可以方便地实现对象间的一对多依赖关系,使得当一个对象状态改变时,其依赖对象会收到通知并自动更新。

// 定义一个事件中心类,用于管理事件的订阅、发布等操作
class EventEmitter {
    constructor() {
        // 用于存储不同事件类型对应的回调函数列表
        this.events = {};
    }

    // on方法用于订阅事件,接收事件名称和回调函数作为参数
    on(eventName, callback) {
        if (!this.events[eventName]) {
            this.events[eventName] = [];
        }
        this.events[eventName].push(callback);
    }

    // off方法用于取消订阅事件,可根据事件名称和具体的回调函数来取消指定的订阅
    off(eventName, callback) {
        if (this.events[eventName]) {
            const index = this.events[eventName].indexOf(callback);
            if (index!== -1) {
                this.events[eventName].splice(index, 1);
            }
            // 如果该事件对应的回调函数列表为空了,删除这个事件类型的记录
            if (this.events[eventName].length === 0) {
                delete this.events[eventName];
            }
        }
    }

    // once方法用于订阅只执行一次的事件,内部借助on方法和一个标记函数来实现
    once(eventName, callback) {
        const onceCallback = (...args) => {
            callback(...args);
            this.off(eventName, onceCallback);
        };
        this.on(eventName, onceCallback);
    }

    // emit方法用于触发事件,接收事件名称以及可选的参数,会依次执行该事件对应的所有回调函数
    emit(eventName,...args) {
        if (this.events[eventName]) {
            this.events[eventName].forEach(callback => callback(...args));
        }
    }
}

// 使用示例
const eventEmitter = new EventEmitter();

// 订阅事件 'event1'
const callback1 = (data) => {
    console.log('事件1触发,收到数据:', data);
};
eventEmitter.on('event1', callback1);

// 订阅只执行一次的事件 'event2'
const callback2 = (data) => {
    console.log('一次性事件2触发,收到数据:', data);
};
eventEmitter.once('event2', callback2);

// 触发 'event1' 事件
eventEmitter.emit('event1', '来自事件1的消息');
// 再次触发 'event1' 事件,依然会执行对应的回调函数
eventEmitter.emit('event1', '又一次来自事件1的消息');

// 触发 'event2' 事件,只会执行一次对应的回调函数
eventEmitter.emit('event2', '来自一次性事件2的消息');
// 再次触发 'event2' 事件,由于已经取消订阅,不会执行回调函数了

// 取消订阅 'event1' 中的 callback1
eventEmitter.off('event1', callback1);
// 再次触发 'event1' 事件,因为已经取消订阅,所以不会执行任何回调函数了
eventEmitter.emit('event1', '这是取消订阅后触发的消息');

在上述代码中:

  1. EventEmitter 类结构及功能

    • constructor:构造函数中初始化了一个空对象 this.events,用于存储不同事件对应的回调函数列表。例如,'event1' 事件对应的回调函数都会存储在 this.events['event1'] 数组中。
    • on 方法:首先判断对应事件名称的回调函数列表是否已存在,如果不存在则创建一个空数组。然后将传入的回调函数添加到对应事件的回调函数列表中,这样后续当该事件被触发时,所有添加的回调函数都会被执行。
    • off 方法:针对指定的事件名称和回调函数,先查找该回调函数在对应列表中的索引,如果能找到(索引不为 -1),则从列表中删除这个回调函数。并且如果该事件的回调函数列表为空了,就从 this.events 中删除这个事件的记录,释放内存。
    • once 方法:创建一个新的内部回调函数 onceCallback,在这个函数内部先执行传入的原始回调函数 callback,然后立即调用 off 方法取消对该事件的这次订阅,从而实现只执行一次的效果。之后将这个内部回调函数添加到对应事件的订阅列表中,借助已有的 on 方法实现功能。
    • emit 方法:根据传入的事件名称查找对应的回调函数列表,如果存在,则遍历列表,依次执行每个回调函数,并将额外传入的参数传递给这些回调函数,实现通知所有订阅者的功能。
  2. 使用示例说明

    • 首先创建了 EventEmitter 实例 eventEmitter,然后通过 on 方法订阅了 'event1' 事件,对应的回调函数 callback1 会在 'event1' 每次触发时被执行。
    • 接着使用 once 方法订阅了 'event2' 事件,对应的回调函数 callback2 只会在 'event2' 首次触发时执行,之后就自动取消订阅了。
    • 通过多次调用 emit 方法来触发不同的事件,展示了订阅、取消订阅以及一次性订阅的实际效果,验证了各个方法的功能是否符合预期。

这样实现的观察者模式可以灵活应用在很多场景中,比如DOM事件处理、组件间通信等,方便地管理不同对象之间的依赖关系和消息通知机制。你可以根据实际需求进一步扩展和优化这个代码,例如添加事件类型的合法性检查、对更多参数的处理等功能。

;