# Technical Mock Interview ## Overview One of the most important concepts in JavaScript is the idea of Events. The Event Emitter pattern is central to web development. ### Question #### Create an Event Emitter Class from Scratch with the Following Methods (30 mins) **You are only allowed to use the [Nodejs Documentation](https://nodejs.org/api/events.html#events_events) and the [MDN Documentation](https://developer.mozilla.org/en-US/)** **addListener(eventName, handlerToBeAdded)** - Be able to add listeners to an object/Register an event - eventName is the name of the event being listened to - handlerToBeAdded is the event handler function - https://nodejs.org/api/events.html#events_event_newlistener **on(eventName, handlerToBeAdded)** - An alias for addListener - https://nodejs.org/api/events.html#events_emitter_on_eventname_listener **removeListener(eventName, handlerToBeRemoved)** - Be able to remove listeners from the object - eventName is the name of the event we are trying to remove - handlerToBeRemoved is event handler function - https://nodejs.org/api/events.html#events_event_removelistener **off(eventName, handlerToBeRemoved)** - Alias for removeListener - https://nodejs.org/api/events.html#events_emitter_off_eventname_listener **emit(eventName, ...eventData)** - eventName is the name of the event - ...eventDate is the list of arguments being supplied - Synchronously calls each of the events registered to eventName - https://nodejs.org/api/events.html#events_emitter_emit_eventname_args **getListeners(eventName)** - Return the listeners registered to the event name - https://nodejs.org/api/events.html#events_emitter_rawlisteners_eventname **getListenersLength(eventName)** - Return the length of the array of listeners registered to the event name - https://nodejs.org/api/events.html#events_emitter_listenercount_eventname **[Extra Credit] once(eventName, handlerToAddThenRemove)** - Be able to add a one time listener to our object, and when we emit it, it's immediately removed - eventName is the name of the event - handlerToAddThenRemove is the event handler funciton - https://nodejs.org/api/events.html#events_emitter_once_eventname_listener Demo of EventEmitter Class in Node: ```javascript /* Event emitters are a common pattern for "registering" (storing) functions to be executed at a later time in response to some sort of arbitrary "event". */ // Example usage of the in built Event Emitter const EventEmitter = require('events') // Create new EventEmitter const ee = new EventEmitter() // Register an event with the name 'event' ee.on('event', () => { console.log('an event occurred!'); }) // "Call" the event with the name 'event' executing everything attached to it synchronously ee.emit('event') ``` #### Solution ```javascript class CoolerEventEmitter { constructor(listeners = {}) { this.listeners = listeners } /* * addListener(eventName, cb) * 1. Check if eventName exists already in our listener object * 2. If yes, return that array * 3. If no, return an empty array * 4. Push cb into our array */ addListener(eventName, cb) { this.listeners[eventName] = this.listeners[eventName] || [] return this.listeners[eventName].push(cb) } /* * on(eventName, cb): Alias for addListener */ on(eventName, cb) { return this.addListener(eventName, cb) } /* * removeListener(eventName, cb) * 1. Make sure that eventName exists; if not, return false * 2. If it does, splice that array at the index of the cb */ removeListener(eventName, cb) { let temp = this.listeners[eventName] if(!temp) return false return temp.splice(temp.indexOf(cb), 1) } /* * off(eventName, cb): Alias for removeListener */ off(eventName, cb) { return this.removeListener(eventName, cb) } /* * emit(eventName, ...args) * 1. Make sure eventName exists; if not, return false * 2. Call the arguments on every element of the array */ emit(eventName, ...args) { let temp = this.listeners[eventName] if (!temp) return false return temp.forEach((f) => { f(...args) }) } /* * once(eventName, cb) * 1. Same idea as addListener/on: Check if eventName exists in the object * 2. If yes, return that array * 3. If no, return empty array * 4. Define a wrapper function and it will fire the cb as well as remove the listener * 5. Push the wrapper function into the array */ once(eventName, cb) { this.listeners[eventName] = this.listeners[eventName] || [] const wrapper = () => { cb() return this.off(eventName, wrapper) } return this.listeners[eventName].push(wrapper) } /* * getListeners(eventName) */ getListeners(eventName) { return this.listeners[eventName] } /* * getListenerLength(eventName) */ getListenerLength(eventName) { let temp = this.listeners[eventName] return temp.length } } ``` ### [Replit](https://repl.it/join/vatmzgqf-b17z)