Как сделать передачу аргументов?

Как правильно сделать, чтобы проходил тест?

Задание: Cоздайте класс EventEmitter для управления событиями. У этого класса должны быть следующие методы: .on(event, callback) - добавить обработчик события

.off(event, callback) - удалить обработчик события

.once(event, callback) - добавить обработчик события, который сработает единожды

.emit(event, [...arg]) - вызвать все обработчики события event, можно передать аргументы

Расширьте EventEmitter классом BroadcastEventEmitter так, чтобы была возможность вызвать все обработчики всех событий: emit("*", [...arg]) - вызвать все обработчики событий, можно передать аргументы

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

 on(eventName, callback) {
     !this.events[eventName] && (this.events[eventName] = []);
     this.events[eventName].push(callback);
 }

 off(eventName, callback) {
     this.events[eventName] = this.events[eventName].filter(eventCallback => callback !== eventCallback);}

once(eventName, callback) {
   this.events[eventName] = this.events[eventName] || [];
     const onceEvent = () => {
         callback();
         this.off(eventName, onceEvent);
     }
     this.events[eventName].push(onceEvent);
     return this;
 }

 emit(eventName, args) {
    const event = this.events[eventName];
    event && event.forEach(callback => callback.call(null, args));
 }
}

class BroadcastEventEmitter extends EventEmitter {
 emit(event, ...args) {
     if (event === '*') {
         Object.keys(this.events).forEach((e) => super.emit(e, ...args));
     } else {
         super.emit(event, ...args);
     }
 }}

Не проходит тест:
тестирование класса BroadcastEventEmitter

✓ проверка наследования от EventEmitter (1ms)

✓ вызов всех событий

✕ передача аргументов (4ms)

  ● тестирование класса BroadcastEventEmitter › передача аргументов

expect(jest.fn()).toHaveBeenCalledWith(...expected)

Expected: 1, 2
Received: 1

Number of calls: 1

  163 |     emitter.emit('*', ...args);
  164 | 
> 165 |     expect(mockFirstListener).toHaveBeenCalledWith(...args);
      |                               ^
  166 |     expect(mockSecondListener).toHaveBeenCalledWith(...args);
  167 |   });
  168 | });

  at Object.toHaveBeenCalledWith test.js:165:31)

Ответы (2 шт):

Автор решения: Neverm1ndo

В методе BroadcastEventEmitter.emit, в обращении к методу наследующего класса super.emit(event, ...args), для передачи использовался оператор rest. Из-за него передавался только 1 аргумент, самый первый.

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

  on(eventName, callback) {
    !this.events[eventName] && (this.events[eventName] = []);
    this.events[eventName].push(callback);
  }

  off(eventName, callback) {
    this.events[eventName] = this.events[eventName].filter(eventCallback => callback !== eventCallback);
  }

  once(eventName, callback) {
    this.events[eventName] = this.events[eventName] || [];
    const onceEvent = (args) => {
      callback.call(onceEvent, args);
      this.off(eventName, onceEvent);
    };
    this.events[eventName].push(onceEvent);
    return this;
  }

  emit(eventName, ...args) {
    const event = this.events[eventName];
    event && event.forEach(callback => callback.call(null, ...args));
  }
}

class BroadcastEventEmitter extends EventEmitter {
  emit(event, ...args) {
    if (event !== '*') return void(super.emit(event, args));
    Object.keys(this.events).forEach((e) => super.emit(e, args));
  }
}

const emitter = new BroadcastEventEmitter();

emitter.on('event', (args) => console.log(args));
emitter.once('event3', (args) => console.log(args));

emitter.emit('event3', 1, 2, 3, 4, 5);
emitter.emit('event', 1, 2, 3, 4, 5);

Попробуйте, прогоните через тест, если что, поправлю ответ.

→ Ссылка
Автор решения: Виталий Пустовой
class EventEmitter {
    constructor() {
        this.events = {};
    }

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

    off(eventName, callback) {
        if (!this.events[eventName]) return;
        this.events[eventName] = this.events[eventName].filter(
            eventCallback => callback !== eventCallback);
    }

    once(eventName, callback) {
        const onceEvent = (...args) => {
            callback.apply(null, args);
            this.off(eventName, onceEvent);
        };
        this.on(eventName, onceEvent);
    }

    emit(eventName, ...args) {
        const event = this.events[eventName];
        if (event) {
            event.forEach((callback) => callback.apply(null, args));
        }
    }
}

class BroadcastEventEmitter extends EventEmitter {
    emit(event, ...args) {
        if (event !== '*') {
            super.emit(event, ...args);
        } else {
            Object.keys(this.events).forEach((e) => super.emit(e, ...args));
        }
    }
}

Я сейчас решал эту задачу, вот самый верный и рабочий ответ. Уверен будущим поколениям пригодится

→ Ссылка