Как реализовать функцию compose, принимающую неограниченное количество функций и аргументов и вызывающую их по цепочке
Что проверяют
Умеете ли вы обращаться с функциями как со значениями: rest-параметры, замыкания, reduce. Код короткий, поэтому смотрят на детали: в каком порядке идут вызовы и что получает самая первая функция цепочки. Следом обычно просят написать pipe или версию для асинхронных функций.
Как отвечать
Начните с контракта: compose(f, g, h)(x) равно f(g(h(x))), функции выполняются справа налево. Самая правая принимает все исходные аргументы, каждая следующая получает одно значение, результат предыдущей.
function compose(...fns) {
if (fns.length === 0) return (x) => x;
return fns.reduce((f, g) => (...args) => f(g(...args)));
}Что стоит проговорить вслух:
- пустой вызов:
reduceбез начального значения на пустом массиве бросаетTypeError, поэтомуcompose()возвращает функцию тождества; - проверка аргументов: если заранее проверить
typeof fn === 'function', ошибка всплывёт при сборке цепочки, а не при первом вызове где-то в глубине приложения; pipe: то же самое слева направо,(...args) => g(f(...args)). В коде его читать проще, порядок совпадает с порядком выполнения;- асинхронная версия:
(x) => fns.reduceRight((p, fn) => p.then(fn), Promise.resolve(x)), каждое звено ждёт предыдущее; - глубина стека: каждая функция добавляет уровень вложенного замыкания. На сотнях звеньев надёжнее обычный цикл по массиву с конца.
Где спотыкаются
Передают массив аргументов первой функции одним значением: reduceRight((acc, fn) => fn(acc), args). Самая правая функция получает не 2, а [2], и x + 1 превращается в конкатенацию строки '21'. Пример при этом «работает», пока его не запустить.
Путают compose и pipe: пишут выполнение слева направо и называют это композицией. Интервьюер почти всегда проверяет порядок на двух некоммутативных функциях, например прибавить единицу и умножить на два.
Разворачивают массив через fns.reverse() прямо внутри возвращаемой функции. Метод мутирует исходный массив, и при каждом следующем вызове порядок меняется на противоположный.