8. Implement an EventEmitter — on, off, emit, once

medium

The EventEmitter is the observer pattern in disguise — the backbone of Node's events, the DOM, and most state libraries.

Design choices that score points

  • Map<string, Set<fn>> — O(1) add/remove and automatic dedupe of the same handler.
  • Copy the set before emitting — otherwise a handler that calls off() (common with once) mutates the collection you're iterating.
  • Return this so calls chain.

Follow-ups

  • "How does once remove itself?" → the wrapper calls off before delegating.
  • "Wildcard or namespaced events?" → maintain a separate '*' listener list, or split on :.
  • "Memory leaks?" → expose removeAllListeners(event) and document that callers must off.

What to practice

Build it, then add once without leaking the wrapper reference — the subtle part is removing the wrapper, not the original fn.

More questions

index.js
class EventEmitter {
  // your code here
}

const bus = new EventEmitter();
const fn = (x) => console.log('got', x);
bus.on('data', fn);
bus.emit('data', 42); // got 42
bus.off('data', fn);
bus.emit('data', 99); // (nothing)

Tests

Test Code

Enter JavaScript that runs after your solution. It should return a value or a Promise.