ES6 Event Emitter

rendezvous with cassidoo issue #132

by Jesse Rogers

HTML

<div id="wrapper">
  <strong id="message">Don't do it. Don't press W.</strong>
</div>

CSS

* {
  box-sizing: border-box;
  font-family: monospace;
}

html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}

#wrapper {
  background: #212121;
  height: 100%;
  left: 0;
  position: fixed;
  top: 0;
  width: 100%;
}

#wrapper strong {
  color: yellow;
  left: 50%;
  margin: 0;
  text-align: center;
  position: absolute;
  top: 50%;
  transform: translate(-50%, -50%);
}

#wrapper.omg {
  background: #ed4e39
}

#wrapper.omg strong {
  color: white;
}

JavaScript

// rendezvous with cassidoo issue #132
// Write an event emitter that has three methods: on, emit, and removeListener.
// The `on` function takes in an event name and a callback function, the `emit`
// function takes in an event name and data (which will be passed to the
// associated callback), and `removeListener` takes in an event name and a callback
// to remove from that event.

class EventEmitter {

	constructor() {
  	this.events = new Map();
  }
  
  /**
  	* @param eventName: string
    * @param callback: (args: any[]) => void
   */
  on(eventName, callback) {
  	// check for existing listeners on this event name
    const callbacks = this.events.get(eventName);
		// if existing listeners, just add to the list
		if (callbacks) {
      callbacks.push(callback);
    } else {
    	// otherwise, create a new array of listeners
      // for the event name
      this.events.set(eventName, callback ? [callback] : []);
    }
  }
  
  /**
   * @param eventName: string
   * @param args: any[]
  */
  emit(eventName, args = []) {
  	// retrieve all registered callbacks for the event name
    const callbacks = this.events.get(eventName);
  	// no callback(s), exit early
    if (!callbacks) {
    	console.error('No listener for ' + eventName);
      return;
    }
    // if contextual arguments supplied, pass them to callbacks
    if (callbacks && args) {
      callbacks.forEach(callback => callback(...args));
    } else {
    	// no data/context, just fire the method
      callbacks.forEach(callback => callback());
    }
  }
  
  /**
   * @param eventName: string
   * @param callback: (args: any[]) => void
  */
  removeListener(eventName, callback) {
  	// if nothing to delete, do nothing
    if (!this.events.get(eventName)) {
      return;
    }
    // remove event from map
    this.events.delete(eventName);
    // dispose of callback function
    if (callback) {
      callback();
    }
  }
  
}

// instantiate emitter instance
const emitter = new EventEmitter();
//...