Simple Event Emitter in JavaScript
Event emitters are a fundamental pattern in many programming languages, allowing objects to notify multiple listeners when a specific event occurs. This challenge asks you to implement a basic event emitter in JavaScript, enabling you to understand the core principles behind this powerful design pattern. Building this will give you a solid foundation for working with libraries and frameworks that utilize event-driven architectures.
Problem Description
You are tasked with creating a JavaScript class called EventEmitter. This class should allow users to:
- Subscribe to events: A user should be able to register a callback function to be executed when a specific event is emitted. This registration should be done using a method called
on(eventName, callback). - Emit events: A user should be able to trigger an event, which will then execute all registered callbacks for that event. This should be done using a method called
emit(eventName, ...args). The...argsshould be passed as arguments to the callbacks. - Remove subscriptions: A user should be able to remove a previously registered callback function using a method called
off(eventName, callback). This should only remove the exact callback function provided, not all callbacks for that event name. - Handle multiple listeners: The emitter should support multiple callbacks registered for the same event. All registered callbacks should be executed when the event is emitted.
Expected Behavior:
on(eventName, callback): Registerscallbackto be executed wheneventNameis emitted.emit(eventName, ...args): Executes all registered callbacks foreventName, passing...argsas arguments.off(eventName, callback): Removescallbackfrom the list of listeners foreventName. If the callback is not found, the function should do nothing.- If an event is emitted and no listeners are registered for that event, the function should do nothing.
Edge Cases to Consider:
- What happens if
onis called with invalid arguments (e.g.,eventNameis not a string,callbackis not a function)? (For simplicity, you can ignore argument validation in this challenge.) - What happens if
emitis called with an event name that has no listeners? - What happens if
offis called with an event name that has no listeners, or with a callback that was never registered? - What happens if
offis called with an invalid callback (e.g., not a function)? (For simplicity, you can ignore argument validation in this challenge.)
Examples
Example 1:
Input:
let emitter = new EventEmitter();
emitter.on('data', (x) => console.log(x));
emitter.emit('data', 1);
emitter.emit('data', 2);
Output:
1
2
Explanation:
The 'data' event is emitted twice, and the callback function logs the provided argument to the console each time.
Example 2:
Input:
let emitter = new EventEmitter();
let callback1 = (x) => console.log(x);
let callback2 = (x) => console.log(x * 2);
emitter.on('data', callback1);
emitter.on('data', callback2);
emitter.emit('data', 5);
emitter.off('data', callback1);
emitter.emit('data', 10);
Output:
10
20
Explanation:
Initially, both callbacks are registered for the 'data' event. The first emit executes both, logging 5 and 10. `callback1` is then removed. The second emit only executes `callback2`, logging 20.
Example 3: (Edge Case)
Input:
let emitter = new EventEmitter();
emitter.emit('nonExistentEvent');
Output:
(No output)
Explanation:
The 'nonExistentEvent' event is emitted, but there are no listeners registered for it, so nothing happens.
Constraints
- The
EventEmitterclass should be implemented using JavaScript. - The
on,emit, andoffmethods must be implemented as described above. - The code should be reasonably efficient. While performance is not the primary focus, avoid unnecessary complexity.
- The class should be well-structured and easy to understand.
Notes
- Consider using a data structure (e.g., an object or a map) to store the event listeners.
- The
offmethod requires careful comparison of callback functions to ensure that only the exact callback is removed. JavaScript's strict equality (===) is recommended for this comparison. - This is a simplified event emitter. Real-world event emitters often include features like error handling, event prioritization, and more sophisticated listener management. Focus on the core functionality for this challenge.