[Medium] LeetCode JS 30 - Event Emitter
2024年3月3日
💎 加入 E+ 成長計畫 與超過 500+ 位軟體工程師一同在社群中成長,並且獲得更多的軟體工程學習資源
LeetCode 30 Days of JavaScript
本题来自 LeetCode 的 30 天 JacaScript 挑战
题目描述
设计一个 EventEmitter 类别
这个类别应该与 Node.js 或 DOM 中的 Event Target 类似,其中包含订阅事件以及发送事件两个方法。
本题要实作的两个方法如下:
subscribe
- 此方法接受两个参数:事件名称(字串)以及一个回呼函式(callback function)。当事件被发送时,该回呼函式会被呼叫。一个事件可以注册多个监听器(listener)。当发送带有多个回呼函式的事件时,每个回呼函式都会按照订阅顺序进行呼叫。并且应返回一个结果阵列。可以假设传递给subscribe
的回呼函式皆不相同。subscribe
方法还会回传一个带有unsubscribe
方法的物件,该物件可以让使用者取消订阅。当呼叫它时,会从订阅列表中删除回呼函式,并返回 undefined。- emit - 此方法接受两个参数:事件名称(字串)以及一个可选的参数阵列,这些参数会被传递给回呼函式。如果没有订阅给定事件的回呼函式,则返回一个空阵列。否则,返回按订阅顺序存下的所有回呼函式回传的结果阵列。
// 范例
输入:
actions = ["EventEmitter", "emit", "subscribe", "subscribe", "emit"],
values = [[], ["firstEvent", "function cb1() { return 5; }"], ["firstEvent", "function cb1() { return 6; }"], ["firstEvent"]]
输出: [[],["emitted",[]],["subscribed"],["subscribed"],["emitted",[5,6]]]
解释:
const emitter = new EventEmitter();
emitter.emit("firstEvent"); // [], 还没有 callback 被订阅
emitter.subscribe("firstEvent", function cb1() { return 5; });
emitter.subscribe("firstEvent", function cb2() { return 6; });
emitter.emit("firstEvent"); // [5, 6], 回传 cb1 与 cb2 的呼叫结果
本题解答
以下是本题的解答,详细解题思路可以在 E+ 成长计划看到。如果想练习更多题目,推荐可以到 GreatFrontEnd 上练习
解法
class EventEmitter {
constructor() {
this.events = new Map();
}
subscribe(eventName, callback) {
if (!this.events.has(eventName)) {
this.events.set(eventName, []);
}
const events = this.events.get(eventName);
events.push(callback);
return {
unsubscribe: () => {
const index = events.indexOf(callback);
if (index !== -1) {
events.splice(index, 1);
}
},
};
}
emit(eventName, args = []) {
if (!this.events.has(eventName)) {
return [];
}
const result = [];
const events = this.events.get(eventName);
events.forEach((callback) => {
result.push(callback(...args));
});
return result;
}
}