1// Subscribe -> needs to return a release function so subscriber no longer receives event2// Thinking of a map of eventName: -> callbackArray so we can have multiple subscribers to the same event3// Emit -> lookup the event name in the map -> loop through callbackArray and relay args to each callback call4// Release -> need to remove the subscriber from the event's callbackArray5class EventEmitter {6constructor() {7// Initialize an event -> callbackArray map8this.eventMap = {};9}1011subscribe(eventName, callback) {12// We wrap the callback in another function that returns the callback so we have a new reference that will help us with filtering the proper subscription in the release function13// even if there are multiple subscriptions using the same callback1 for example14const subscribedCallback = () => callback;15// If there is an existing eventName to subscribe to, push the callback onto the array16if (this.eventMap[eventName]) {17this.eventMap[eventName].push(subscribedCallback);18} else {19// Otherwise, we initialize it with a new array with the 1 callback inside20this.eventMap[eventName] = [subscribedCallback];21}2223// Need to return an object with a release function that will remove the callback from the event's array24// We have closure around the subscribedCallback reference so we can filter out the exact subscription later25const self = this;26return {27release: function release() {28if (self.eventMap[eventName]) {29// Remove the subscribedCallback from the event's callback array30self.eventMap[eventName] = self.eventMap[eventName].filter((currentCallback) => subscribedCallback !== currentCallback);3132// If there are no more callbacks subscribed to the event, we can remove the event from the map33if (self.eventMap[eventName].length === 0) {34delete self.eventMap[eventName];35}36}37}38}39}4041emit(eventName, ...args) {42// If the event doesn't exist in the map, do nothing43if (!this.eventMap[eventName]) {44return;45}4647// Otherwise, we will loop through the event's callback array and apply the callbacks with relayed args48this.eventMap[eventName].forEach((subscribedCallback) => {49const currentCallback = subscribedCallback();50currentCallback.apply(this, args);51});52}53}5455const emitter = new EventEmitter();5657const callback1 = (...args) => { console.log(`Callback 1 ${args}`); };58const callback2 = () => { console.log("Callback2"); };59const sub1 = emitter.subscribe('event1', callback1);60const sub2 = emitter.subscribe('event2', callback2);6162emitter.emit("event1", 1, 2);63emitter.emit("event2");6465// same callback could subscribe66// on same event multiple times67const sub3 = emitter.subscribe('event1', callback1);6869emitter.emit("event1", 1,2,3);7071console.log("Releasing sub1");72sub1.release();73emitter.emit("event1", 4, 5);74console.log("Releasing sub3");75sub3.release();76emitter.emit("event1", 5, 6);77console.log("Releasing sub2");78sub2.release();79emitter.emit("event2");