iT邦幫忙

2023 iThome 鐵人賽

DAY 28
0
Software Development

LeetCode-30 Days of JavaScript系列 第 28

LeetCode JS30-Day28 | 2694. Event Emitter 事件發送器

  • 分享至 

  • xImage
  •  

LeetCode JS30-Day28 | 2694. Event Emitter 事件發送器 Medium

Description❓

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.

Your EventEmitter class should have the following two methods:

  • 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.
  • 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.

設計一個EventEmitter類別,此介面與 Node.js 或 DOM 的目標事件介面類似(但有一些差異)。
EventEmitter 應該允許訂閱事件以及觸發事件。

EventEmitter類別應該有以下兩種方法:

  • subscribe
    • 此方法接受兩個參數:字串形式的事件名稱和回調函數,當事件觸發時將調用這個回調函數。
    • 一個事件應該能夠有多個監聽器,當觸發具有多個回調函數的事件時,應按照訂閱順序調用回調函數並傳回一個包含調用結果的陣列。
    • 你可以假設傳遞給subscribe的回呼函數不會是引用相同的。 (不會將相同的回調函數多次註冊到同一事件上,每個回調函數都是獨立的)
    • subscribe方法應該回傳一個包含unsubscribe方法的物件使用戶能夠取消訂閱,當它被呼叫時,回調函數應該從訂閱列表中刪除,並且應該返回undefined
  • emit
    • 此方法接受兩個參數:作為字串的事件名稱和將傳遞給回調函數的可選參數陣列。
    • 如果沒有訂閱給定事件的回調函數,則傳回空陣列。否則,按訂閱順序傳回所有回調函數調用結果的陣列。

Points

Solution✍️

[ ▶️挑戰這一題 ][ 本日代碼 ]

class EventEmitter {
  //`constructor()`建構函數邏輯:一個事件可以註冊多個監聽器。
  //建構函示使用Map儲存鍵值對 [event,cbs]的集合
  constructor() {
    this.events = new Map();
  }

  //註冊監聽
  //訪問 鍵值對 取得 屬性值 陣列cbs,將回調函數push至陣列cbs內。
  //(如key不存在添加一個屬性值為[]的初始化的鍵值對)
  subscribe(event,cb) {    
    if (!this.events.has(event)) {
      this.events.set(event, []);
    }
    const cbs = this.events.get(event);
    cbs.push(cb);
    //回傳取消訂閱的方法`unsubscribe`
    // 取得 cb 在 cbs 陣列中的索引值
    // 使用 Array.splice(index, num)方法刪除回調函數
    const unsubscribe = () => {
      const index = cbs.indexOf(cb);
      if (index >= 0 ) {
        cbs.splice(index, 1);
      }
      return undefined;
    }
    return { msg: "subscribed", unsubscribe: unsubscribe };
  }

  // `emit`觸發邏輯
  emit(event, args) {
    let results = [];
    //Map中key不存在時返回空陣列
    if (!this.events.has(event)) {
      return results;
    }
    //傳回按順序調用cbs的結果陣列
    const cbs = this.events.get(event);
    for (const cb of cbs) {
      results.push(cb(...args));
    }
    return results;
  }
}

Testcase

let test1 =[];
const emitter1 = new EventEmitter();
test1[1]=emitter1.emit("firstEvent",[]);
test1[2]=emitter1.subscribe("firstEvent", function cb1() { return 5; });
test1[3]=emitter1.subscribe("firstEvent", function cb2() { return 6; });
test1[4]=emitter1.emit("firstEvent",[]); 
console.log(`[test1] ${JSON.stringify(test1)}`);
//[test1] [null,[],{"msg":"subscribed"},{"msg":"subscribed"},[5,6]]
let test2 =[];
let emitter2 = new EventEmitter();
test2[1]=emitter2.subscribe("firstEvent", function cb1(...args) { return args.join(','); });
test2[2]=emitter2.emit("firstEvent", [1, 2, 3]); 
test2[3]=emitter2.emit("firstEvent", [3, 4, 6]); 
console.log(`[test2] ${JSON.stringify(test2)}`);
//[test2] [null,{"msg":"subscribed"},["1,2,3"],["3,4,6"]]
let test3 =[];
const emitter3 = new EventEmitter();
const sub = emitter3.subscribe("firstEvent", (...args) => args.join(','));
test3[1]= sub;
test3[2]= emitter3.emit("firstEvent", [1, 2, 3]); 
test3[3]= sub.unsubscribe(); 
test3[4]= emitter3.emit("firstEvent", [4, 5, 6]);
console.log(`[test3] ${JSON.stringify(test3)}`);
//[test3] [null,{"msg":"subscribed"},["1,2,3"],null,[]]
let test4 =[];
const emitter4 = new EventEmitter();
const sub1 = emitter4.subscribe("firstEvent", x => x + 1);
test4[1]=sub1;
const sub2 = emitter4.subscribe("firstEvent", x => x + 2);
test4[2]=sub2;
test4[3]=sub1.unsubscribe(); 
test4[4]= emitter4.emit("firstEvent", [5]); 
console.log(`[test4] ${JSON.stringify(test4)}`);
//[test4] [null,{"msg":"subscribed"},{"msg":"subscribed"},null,[7]]


上一篇
LeetCode JS30-Day27 | 2705. Compact Object 緊湊物件
下一篇
LeetCode JS30-Day29 | 2695. Array Wrapper 包裝陣列
系列文
LeetCode-30 Days of JavaScript30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言