Implement an Event Emitter in JavaScript

This is one of the most asked interview questions and In this interview article, we’ll dive deep into creating a robust Event Emitter in JavaScript, exploring its core functionalities and potential enhancements. This concept is also called as Publisher-Subscriber(Pub-Sub) Design pattern.

Understanding the Event Emitter:

An Event Emitter is a design pattern that allows different parts of your application to communicate through events. It provides a way to register event listeners, emit events, and remove listeners, enabling loose coupling between components.

Core Features of an Event Emitter that we will be covering as part of this article.

  • Registering Event Listeners: Add functions (listeners) that should be called when a specific event occurs.
  • Emitting Events: Trigger events, invoking all registered listeners for that event.
  • Removing Event Listeners: Remove specific listeners or all listeners for an event.

Implementing the Event Emitter: Step-By-Step

Let’s build a comprehensive EventEmitter class that incorporates these features.

1. Create the Class

We’ll start by defining the EventEmitter class with a constructor containing an events object. Here we can have an Events Map as well instead of an object.

class EventEmitter {
  constructor() {
    this.events = {};
  }
}

2. Registering Event Listeners

The on method allows us to register a listener for a specific event. If the event doesn’t exist, we initialize it with an empty array and then push the listener into the array.

on(event, listener) {
  if (!this.events[event]) {
    this.events[event] = [];
  }
  this.events[event].push(listener);
}

3. Emitting Events

The emit method triggers an event. It calls all registered listeners for the event with the provided arguments.

emit(event, ...args) {
  if (!this.events[event]) {
    return;
  }
  this.events[event].forEach(listener => listener(...args));
}

4. Removing Event Listeners

The off method removes a specific listener for an event, while the offAll method removes all listeners for an event.

off(event, listenerToRemove) {
  if (!this.events[event]) {
    return;
  }
  this.events[event] = this.events[event].filter(listener => listener !== listenerToRemove);
}

offAll(event) {
  if (this.events[event]) {
    delete this.events[event];
  }
}


5. Combining all the methods:

class EventEmitter {
  constructor() {
    this.events = {};
  }

  on(event, listener) {
    if (!this.events[event]) {
      this.events[event] = [];
    }
    this.events[event].push(listener);
  }

  emit(event, ...args) {
    if (!this.events[event]) {
      return;
    }
    this.events[event].forEach(listener => listener(...args));
  }

  off(event, listenerToRemove) {
    if (!this.events[event]) {
      return;
    }
    this.events[event] = this.events[event].filter(listener => listener !== listenerToRemove);
  }

  offAll(event) {
    if (this.events[event]) {
      delete this.events[event];
    }
  }
}


Using the Event Emitter:

const emitter = new EventEmitter();

function onData(data) {
  console.log(`Received data: ${data}`);
}

// Register an event listener
emitter.on('data', onData);

// Emit the event
emitter.emit('data', 'sample data');
// Output: Received data: sample data

// Emit the event again
emitter.emit('data', 'sample data');
// Output: Received data: sample data

// Remove the event listener
emitter.off('data', onData);

// Try emitting the event again
emitter.emit('data', 'sample data'); // No output, as the listener has been removed

// Register multiple listeners and remove all
emitter.on('data', data => console.log(`Listener 1: ${data}`));
emitter.on('data', data => console.log(`Listener 2: ${data}`));
emitter.offAll('data');
emitter.emit('data', 'sample data'); // No output, as all listeners have been removed


Implementing an Event Emitter in JavaScript is a powerful way to manage events in your applications. By understanding and extending the basic functionalities, you can create a highly versatile and reusable event system. This approach not only promotes modularity and loose coupling but also enhances the overall maintainability of your code.

1 comment