An event emitter lets one part of a program say "call me when this happens" and another part say "it happened", without either one knowing the other. on(name, fn) adds a listener for an event name. emit(name, ...args) calls every listener of that name, with those arguments. The browser's addEventListener works the same way.
Here is how code uses an emitter, with another event:
const page = new EventEmitter();
page.on("scroll", (y) => console.log("at", y));
page.emit("scroll", 300); // prints: at 300
page.emit("resize"); // nobody listens: nothing runs
The emitter keeps this.listeners: for each name, an array of functions in the order they were added. They run in that order. off(name, fn) removes one listener, and once(name, fn) adds one that runs on the first emit only. One trap: if a listener calls off while emit is looping, the listeners after it must still run.
The check prints every call and the listeners that run. Part of what it must print:
cart.on("add", badge)
cart.on("add", total)
cart.emit("add", "Mug", 12)
badge("Mug", 12) runs
total("Mug", 12) runs
cart.emit("remove", "Mug")
no listener runs
shop.on("checkout", receipt)
shop.once("checkout", thanks)
shop.on("checkout", email)
shop.emit("checkout", 41)
receipt(41) runs
thanks(41) runs
email(41) runs
shop.emit("checkout", 12)
receipt(12) runs
email(12) runs
Your task: the class EventEmitter in solution.js already sets this.listeners = {} and has four empty methods. Fill in on, emit, off and once.
Assignment
Follow the Coding Tutorial to write on and emit, then off with filter, then once with a wrapper that removes itself.
Hintfilter builds a new array, so an emit already looping over the old one goes on to the end. In once, the emitter holds the wrapper, not fn, so the wrapper is what off must remove.
Free plan: 30 tutor messages. PRO is unlimited.
