Параметры функции >reduce
, кроме массива – комбинирующая функция и начальное значение. Эта функция чуть менее понятная, чем >filter
или >map
, поэтому обратите на неё пристальное внимание.
>function reduce(array, combine, start) {
> var current = start;
> for (var i = 0; i < array.length; i++)
> current = combine(current, array[i]);
> return current;
>}
>console.log(reduce([1, 2, 3, 4], function(a, b) {
> return a + b;
>}, 0));
>// → 10
Стандартный метод массивов >reduce
, который, конечно, работает так же, ещё более удобен. Если массив содержит хотя бы один элемент, вы можете не указывать аргумент >start
. Метод возьмёт в качестве стартового значения первый элемент массива и начнёт работу со второго.
Чтобы при помощи >reduce
найти самого древнего из известных моих предков, мы можем написать нечто вроде:
>console.log(ancestry.reduce(function(min, cur) {
> if (cur.born < min.born) return cur;
> else return min;
>}));
>// → {name: "Pauwels van Haverbeke", born: 1535, …}
Как бы мы могли написать предыдущий пример (поиск человека с самой ранней датой рождения) без функций высшего порядка? На самом деле, код не такой уж и ужасный:
>var min = ancestry[0];
>for (var i = 1; i < ancestry.length; i++) {
> var cur = ancestry[i];
> if (cur.born < min.born)
> min = cur;
>}
>console.log(min);
>// → {name: "Pauwels van Haverbeke", born: 1535, …}
Чуть больше переменных, на две строчки длиннее – но пока достаточно понятный код.
Функции высшего порядка раскрывают свои возможности по-настоящему, когда вам приходится комбинировать функции. К примеру, напишем код, находящий средний возраст мужчин и женщин в наборе.
>function average(array) {
> function plus(a, b) { return a + b; }
> return array.reduce(plus) / array.length;
>}
>function age(p) { return p.died - p.born; }
>function male(p) { return p.sex == "m"; }
>function female(p) { return p.sex == "f"; }
>console.log(average(ancestry.filter(male).map(age)));
>// → 61.67
>console.log(average(ancestry.filter(female).map(age)));
>// → 54.56
(Глупо, что нам приходится определять сложение как функцию >plus
, но операторы в JavaScript не являются значениями, поэтому их не передашь в качестве аргументов.)
Вместо того, чтобы впутывать алгоритм в большой цикл, всё распределено по концепциям, которые нас интересуют – определение пола, подсчёт возраста и усреднение чисел. Мы применяем их по очереди для получения результата.
Для написания понятного кода это прямо-таки сказочная возможность. Конечно, ясность не достаётся бесплатно.