Помогите решить задачу плиз
- Найти ошибки в коде
Разработчик Василий торопился на встречу с коллегами, поэтому быстро написал программу. Код получился неидеальным. Помогите Василию исправить ошибки в коде:
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));
- И отправить исправленный вариант в качестве решения.
[["football","Kate"],["hockey","Mary"]]
Ответы (1 шт):
Первая строчка, которая бросается в глаза
fnConstructor.bind(res).call(params);
Что в ней происходит
- устанавливается контекст в
res - полученная функция вызывается с переданным контекстом
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));