Design an EventEmitter class. This interface is similar (but with some differences) to the one found in Node.js or the Event Target interface of the DOM. The EventEmitter should allow for subscribing to events and emitting them.
設計一個EventEmitter class。此介面類似於 Node.js 中的 EventEmitter 或 DOM 中的 Event Target 介面,但有一些差異。這個 EventEmitter 應該允許訂閱和觸發事件。
Your EventEmitter class should have the following two methods:
你的 EventEmitter class 應該有以下兩個方法:
subscribe – This method takes in two arguments: the name of an event as a string and a callback function. This callback function will later be called when the event is emitted.
An event should be able to have multiple listeners for the same event. When emitting an event with multiple callbacks, each should be called in the order in which they were subscribed. An array of results should be returned. You can assume no callbacks passed to subscribe are referentially identical.
The subscribe method should also return an object with an unsubscribe method that enables the user to unsubscribe. When it is called, the callback should be removed from the list of subscriptions and undefined should be returned.
subscribe - 這個方法接受兩個參數:事件的名稱(以字串形式)和回調函式。 當事件被觸發時,將被呼叫回調函式。 一個事件應該能夠有多個監聽器,當觸發一個帶有多個回調函式的事件時, 應按照它們訂閱的順序依序呼叫,結果應該回傳一個陣列。 你可以假設傳遞給 subscribe 的回調函式不會有相同的引用。 subscribe 方法還應該回傳一個對象,該對象具有 unsubscribe 的方法,用於取消訂閱。 當呼叫 unsubscribe 方法時,該回調函式應從訂閱列表中刪除,並回傳 undefined。
emit – This method takes in two arguments: the name of an event as a string and an optional array of arguments that will be passed to the callback(s). If there are no callbacks subscribed to the given event, return an empty array. Otherwise, return an array of the results of all callback calls in the order they were subscribed.
emit - 這個方法接受兩個參數:事件的名稱(以字串形式)和一個可選的參數陣列,這個陣列將傳遞給回調函式。 如果沒有訂閱該事件的回調函式,則回傳一個空陣列。 否則,按照它們訂閱的順序回傳所有回調函式呼叫的陣列結果。
Example 1:
Input: actions = ["EventEmitter", "emit", "subscribe", "subscribe", "emit"], values = [[], ["firstEvent", "function cb1() { return 5; }"], ["firstEvent", "function cb1() { return 5; }"], ["firstEvent"]] Output: [[],["emitted",[]],["subscribed"],["subscribed"],["emitted",[5,6]]]
Example 2:
Input: actions = ["EventEmitter", "subscribe", "emit", "emit"], values = [[], ["firstEvent", "function cb1(...args) { return args.join(','); }"], ["firstEvent", [1,2,3]], ["firstEvent", [3,4,6]]] Output: [[],["subscribed"],["emitted",["1,2,3"]],["emitted",["3,4,6"]]]
Example 3:
Input: actions = ["EventEmitter", "subscribe", "emit", "unsubscribe", "emit"], values = [[], ["firstEvent", "(...args) => args.join(',')"], ["firstEvent", [1,2,3]], [0], ["firstEvent", [4,5,6]]] Output: [[],["subscribed"],["emitted",["1,2,3"]],["unsubscribed",0],["emitted",[]]]
solution:
建立一個 eventMap 的物件來記錄事件和回調函式。
-subscribe方法用於訂閱事件:
當訂閱事件時,確認 eventMap 物件是否已經存在該事件的key。
如果不存在,則創建一個 new Set() 來存儲該事件的回調函式。
然後,將回調函式加入到相應事件的 Set() 中。
最後,回傳一個具有 unsubscribe 方法的物件,該方法可以用於取消訂閱。
當呼叫 unsubscribe 方法時,它會從相應事件的 Set 中刪除該回調函式。
-emit方法用於觸發事件:
它接受一個事件名稱和一個可選的參數陣列作為參數。
該方法首先檢查 eventMap 物件中是否存在該事件的 key。
如果不存在,則回傳一個空陣列表示沒有回調函式被訂閱該事件。
否則,它遍歷該事件的回調函式集合,並依序將結果加入到一個陣列中,最後回傳陣列結果。
Code 1: BigO(1)
class EventEmitter { eventMap = {} subscribe(event, cb) { if (!this.eventMap.hasOwnProperty(event)) { this.eventMap[event] = new Set() } this.eventMap[event].add(cb) return { unsubscribe: () => { this.eventMap[event].delete(cb) } }; } emit(event, args = []) { const res = []; (this.eventMap[event] ?? []) .forEach((cb) => res.push(cb(...args))) return res; }; };
FlowChart:
Example 1
const emitter = new EventEmitter(); console.log(emitter.emit("firstEvent")); // [], no callback are subscribed yet console.log(emitter.subscribe("firstEvent", function cb1() { return 5; })); console.log(emitter.subscribe("firstEvent", function cb2() { return 6; })); console.log(emitter.emit("firstEvent")); // [5, 6], returns the output of cb1 and cb2
Example 2
const emitter = new EventEmitter(); console.log(emitter.subscribe("firstEvent", function cb1(...args) { return args.join(','); })); console.log(emitter.emit("firstEvent", [1, 2, 3])); // ["1,2,3"] console.log(emitter.emit("firstEvent", [3, 4, 6])); // ["3,4,6"]
Example 3
const emitter = new EventEmitter(); const sub = emitter.subscribe("firstEvent", (...args) => args.join(',')); console.log(emitter.emit("firstEvent", [1, 2, 3])); // ["1,2,3"] console.log(sub.unsubscribe()); // undefined console.log(emitter.emit("firstEvent", [4, 5, 6])); // [], there are no subscriptions