推荐答案
// www.javascriptcn.com code example
class EventEmitter {
constructor() {
this.events = {};
}
on(eventName, callback) {
if (!this.events[eventName]) {
this.events[eventName] = [];
}
this.events[eventName].push(callback);
}
emit(eventName, ...args) {
if (this.events[eventName]) {
this.events[eventName].forEach(callback => {
callback(...args);
});
}
}
off(eventName, callback) {
if (this.events[eventName]) {
this.events[eventName] = this.events[eventName].filter(cb => cb !== callback);
}
}
once(eventName, callback) {
const onceCallback = (...args) => {
callback(...args);
this.off(eventName, onceCallback);
};
this.on(eventName, onceCallback);
}
}
// 示例用法
const emitter = new EventEmitter();
const handleData = (data) => {
console.log("收到数据:", data);
};
const handleMessage = (message, sender) => {
console.log(`收到消息: ${message} 来自: ${sender}`);
}
emitter.on("data", handleData);
emitter.on("message", handleMessage)
emitter.emit("data", { id: 1, content: "hello"});
emitter.emit("message", "你好", "user1");
emitter.off("data", handleData);
emitter.emit("data", {id:2, content: 'world'}); // 不会输出
emitter.once('greet', (name) => {
console.log(`Hello, ${name}!`)
})
emitter.emit('greet', 'Alice'); // 输出 Hello, Alice!
emitter.emit('greet', 'Bob') // 不会输出本题详细解读
什么是发布-订阅模式?
发布-订阅模式(Publish-Subscribe Pattern)是一种消息传递模式,它允许不同的组件之间进行松散耦合的通信。在这种模式中,发布者(Publisher)发送消息,而订阅者(Subscriber)接收消息。发布者不知道有哪些订阅者,订阅者也不知道有哪些发布者,它们通过一个中央的事件总线(Event Bus,通常由 EventEmitter 这样的对象实现)进行通信。
核心概念:
- 发布者(Publisher): 发布事件或消息的组件。
- 订阅者(Subscriber): 订阅特定事件或消息的组件,并在事件发生时得到通知。
- 事件总线(Event Bus): 一个中央组件,负责接收发布者的消息并将其分发给所有相应的订阅者。
优点:
- 松耦合: 发布者和订阅者之间不需要彼此了解,降低了组件之间的依赖性。
- 可扩展性: 容易添加新的发布者或订阅者,不会影响现有组件。
- 异步性: 发布者发出消息后不需要等待订阅者处理,可以异步进行。
实现思路
EventEmitter类: 创建一个类,用来管理事件的订阅和发布。events属性: 使用一个对象events来存储事件名和对应的回调函数列表。键是事件名称,值是一个数组,数组中存放该事件的所有回调函数。
on(eventName, callback)方法: 用于订阅事件。- 参数:
eventName(事件名) 和callback(回调函数)。 - 逻辑:
- 如果
events对象中没有eventName对应的数组,就创建一个新的空数组。 - 将
callback添加到eventName对应的回调函数列表中。
- 如果
- 参数:
emit(eventName, ...args)方法: 用于发布事件。- 参数:
eventName(事件名) 和...args(传递给回调函数的参数)。 - 逻辑:
- 如果
events对象中存在eventName对应的回调函数列表,就遍历该列表,依次调用每一个回调函数,并传入...args参数。
- 如果
- 参数:
off(eventName, callback)方法: 用于取消订阅事件。- 参数:
eventName(事件名) 和callback(需要移除的回调函数) - 逻辑:
- 如果
events对象中存在eventName对应的回调函数列表,就使用filter方法过滤掉该callback,更新events中该eventName对应回调函数列表。
- 如果
- 参数:
once(eventName, callback)方法: 用于订阅一次事件,在回调函数执行后自动取消订阅。- 参数:
eventName(事件名) 和callback(回调函数)。 - 逻辑:
- 定义一个内部函数
onceCallback, 当该函数被调用时,先执行callback,然后调用off方法注销onceCallback事件。 - 使用
on方法将onceCallback注册到eventName事件。
- 定义一个内部函数
- 参数:
代码详解
class EventEmitter { ... }: 定义一个EventEmitter类。constructor() { this.events = {}; }: 初始化一个空对象events,用于存储事件和回调函数。on(eventName, callback): 将回调函数添加到指定事件的回调列表中。emit(eventName, ...args): 触发指定事件,并执行所有对应的回调函数,传递args参数。off(eventName, callback): 移除指定事件的某个回调函数。once(eventName, callback): 注册一个只执行一次的回调函数。- 示例用法: 创建一个
EventEmitter实例,订阅和发布事件,以及演示取消订阅和只执行一次的事件。
通过这个例子,你可以理解发布-订阅模式的原理和实现方式。它是一种非常实用的设计模式,在前端开发中被广泛用于处理事件、组件通信等场景。