[Medium] LeetCode JS 30 - Event Emitter
2024年3月3日
💎 加入 E+ 成長計畫 與超過 400+ 位軟體工程師一同在社群中成長,並且獲得更多的軟體工程學習資源
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;
}
}