Помогите решить задачу плиз

  1. Найти ошибки в коде

    Разработчик Василий торопился на встречу с коллегами, поэтому быстро написал программу. Код получился неидеальным. Помогите Василию исправить ошибки в коде:


const participants = ["Mary", "Kate"]

const sports = ["football", "hockey"]

function func(participants, sports) {
  /**  
   * Подобно оператору new создает экземпляр объекта,  
   * используя функцию-конструктор и параметры для нее  
   */
  function constructFrom(fnConstructor, params) {
    const res = {};

    fnConstructor.bind(res).call(params);

    Object.setPrototypeOf(res, fnConstructor);
    return res;
  }

  /**  
   * Создает пары вида [’вид спорта’, ’имя участника’],  
   * где первому виду спорта соответствует последний участник  
   */
  
  function assignParicipants() {
    const participants = this.participants;
    const sports = this.sports;
    const orderIndexes = [];
    let i = sports.length;

    while (i--) {
      orderIndexes.push(function () {
        return i;
      });
    }

    return orderIndexes.map(
      (getSportIndex, i) => [sports[i], participants[getSportIndex()]]
    );
  }

  function Contest(participants, sports) {
    this.participants = participants;
    this.sports = sports;
  }

  Contest.prototype.assignParicipants = assignParicipants;

  const contest = constructFrom(Contest, participants, sports);

  return contest.assignParicipants();
}
console.log(func(participants, sports));
  1. И отправить исправленный вариант в качестве решения.
[["football","Kate"],["hockey","Mary"]]

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

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

Первая строчка, которая бросается в глаза

fnConstructor.bind(res).call(params);

Что в ней происходит

  1. устанавливается контекст в res
  2. полученная функция вызывается с переданным контекстом params, который игнорируется, так как у результата функции bind нельзя сменить контекст.

Очевидно, здесь идет попытка вызвать функцию с переданными параметрами, передав ей в качестве контекста новый объект.

Для этого можно использовать метод .apply

fnConstructor.apply(res, params);

Стоит обратить внимание, что подразумевается возможность передать несколько параметров, поэтому params должен быть коллекцией, содержащей все переданные параметры.

Чтобы добиться этого нужно использовать синтаксис для rest parameters в определении функции

function constructFrom(fnConstructor, ...params) {

В этом случае первый параметр будет помещен в fnConstructor, а все оставшиеся собраны в params.

Далее идет установка прототипа для нового объекта. Стоит обратить внимание, что в качестве прототипа должен устанавливаться прототип функции конструктора, а не сам конструктор

Object.setPrototypeOf(res, fnConstructor.prototype);

Следующий недочет связан с замыканием переменной в цикле. Подробнее о решении этой проблемы можно посмотреть в ответе на вопрос Почему асинхронная функция внутри цикла выполняет последнюю итерацию много раз?

Например, можно сохранять значение счетчика на каждой итерации в переменную объявленную с помощью let.


Исправив указанные недочеты получаем ожидаемый ответ:

const participants = ["Mary", "Kate"]

const sports = ["football", "hockey"]

function func(participants, sports) {
  /**  
   * Подобно оператору new создает экземпляр объекта,  
   * используя функцию-конструктор и параметры для нее  
   */
  function constructFrom(fnConstructor, ...params) {
    const res = {};

    fnConstructor.apply(res, params);

    Object.setPrototypeOf(res, fnConstructor.prototype);
    return res;
  }

  /**  
   * Создает пары вида [’вид спорта’, ’имя участника’],  
   * где первому виду спорта соответствует последний участник  
   */

  function assignParicipants() {
    const participants = this.participants;
    const sports = this.sports;
    const orderIndexes = [];
    let i = sports.length;

    while (i--) {
      let ii = i;
      orderIndexes.push(function() {
        return ii;
      });
    }

    return orderIndexes.map(
      (getSportIndex, i) => [sports[i], participants[getSportIndex()]]
    );
  }

  function Contest(participants, sports) {
    this.participants = participants;
    this.sports = sports;
  }

  Contest.prototype.assignParicipants = assignParicipants;

  const contest = constructFrom(Contest, participants, sports);

  return contest.assignParicipants();
}
console.log(func(participants, sports));

→ Ссылка