jsartisan / frontend-challenges

FrontendChallenges is a collection of frontend interview questions and answers. It is designed to help you prepare for frontend interviews. It's free and open source.
https://frontend-challenges.com
20 stars 3 forks source link

Event Emitter #58

Closed jsartisan closed 1 month ago

jsartisan commented 1 month ago

Info

difficulty: medium
title: Event Emitter
type: question
template: javascript
tags: javascript, events

Question

vent emitters are a fundamental concept in JavaScript for handling asynchronous events and implementing custom event-driven architectures. They allow objects to emit named events that cause previously registered callbacks (listeners) to be called.

Implement an EventEmitter class in JavaScript that provides methods to subscribe to events (on), unsubscribe from events (off), and emit events (emit). The on method should allow multiple listeners to be registered for the same event. The off method should remove specific listeners for an event. The emit method should trigger all listeners for a given event.

Use the following example to understand how the EventEmitter class should work:

const emitter = new EventEmitter();

const callback1 = () => console.log('Callback 1 called');
const callback2 = () => console.log('Callback 2 called');

// Subscribe to the 'event1' event
emitter.on('event1', callback1);
emitter.on('event1', callback2);

// Emit the 'event1' event
emitter.emit('event1');
// Output:
// Callback 1 called
// Callback 2 called

// Unsubscribe callback1 from the 'event1' event
emitter.off('event1', callback1);

// Emit the 'event1' event again
emitter.emit('event1');
// Output:
// Callback 2 called

Template

index.js

export class EventEmitter {

}

index.test.js

import { EventEmitter } from './';

describe('EventEmitter class', () => {
  let emitter;

  beforeEach(() => {
    emitter = new EventEmitter();
  });

  it('should subscribe to events and emit them', () => {
    const callback1 = jest.fn();
    const callback2 = jest.fn();

    emitter.on('event1', callback1);
    emitter.on('event1', callback2);

    emitter.emit('event1');

    expect(callback1).toHaveBeenCalled();
    expect(callback2).toHaveBeenCalled();
  });

  it('should unsubscribe from events', () => {
    const callback1 = jest.fn();
    const callback2 = jest.fn();

    emitter.on('event1', callback1);
    emitter.on('event1', callback2);

    emitter.off('event1', callback1);

    emitter.emit('event1');

    expect(callback1).not.toHaveBeenCalled();
    expect(callback2).toHaveBeenCalled();
  });

  it('should emit events with arguments', () => {
    const callback = jest.fn();

    emitter.on('event1', callback);

    emitter.emit('event1', 'arg1', 'arg2');

    expect(callback).toHaveBeenCalledWith('arg1', 'arg2');
  });

  it('should not fail when unsubscribing from non-existing event', () => {
    const callback = jest.fn();

    emitter.off('non_existing_event', callback);

    expect(callback).not.toHaveBeenCalled();
  });

  it('should not fail when emitting non-existing event', () => {
    const callback = jest.fn();

    emitter.on('event1', callback);

    emitter.emit('non_existing_event');

    expect(callback).not.toHaveBeenCalled();
  });
});

package.json

{
  "dependencies": {},
  "main": "/index.js",
  "devDependencies": {}
}
github-actions[bot] commented 1 month ago

59 - Pull Request updated.