Перейти к содержимому
Теория · Методы массивов · урок 4 из 12

reduce

map и filter возвращают массив, а сумма, максимум или количество — это одно значение. Для таких задач на конвейере нужна не вторая лента, а копилка.

Представьте работника с копилкой у ленты. Перед началом он кладёт в копилку стартовую сумму, например ноль. Каждый подъехавший ящик он вскрывает, добавляет его содержимое к деньгам из копилки и кладёт всё обратно. Когда лента опустеет, в копилке окажется итог.

Метод reduce работает так же: он проходит по массиву и собирает все элементы в одно значение.

JavaScript
const nums = [4, 7, 10];
const sum = nums.reduce((total, n) => total + n, 0);

console.log(sum); // 21

Давайте разберём вызов по частям:

  1. (total, n) => total + n — колбэк, наш работник: он берёт деньги из копилки total и очередной ящик n.
  2. 0 — стартовая сумма в копилке.
  3. reduce возвращает то, что оказалось в копилке в конце, и программа печатает 21.

На собеседовании часто просят посчитать сумму массива через reduce. Этот пример и есть ответ.

Аккумулятор

reduce принимает два аргумента: колбэк и начальное значение, здесь 0. Колбэк получает промежуточный результат и очередной элемент, а возвращает новый промежуточный результат. Промежуточный результат называют аккумулятором; в примере это параметр total.

Имена параметров колбэка выбирают сами: total и n подсказывают читателю, что хранит каждый из них.

Как идут вызовы

Аккумулятор переходит от вызова к вызову по трём правилам:

  1. При первом вызове аккумулятор равен начальному значению.
  2. Каждый следующий вызов получает то, что вернул предыдущий.
  3. Что вернул последний вызов, то и возвращает reduce.

Для [4, 7, 10] вызовы идут так:

totalnколбэк возвращает
044
4711
111021

Нажимайте «Следующий шаг» и следите за total: каждый новый вызов add получает число, которое вернул предыдущий. Колбэк в программе виджета — именованная функция add, чтобы у каждого её вызова была своя рамка. Между рамками script и add лежит рамка самого reduce: метод — тоже функция, он хранит аккумулятор и сам вызывает add для каждого элемента.

ВживуюАккумулятор reduce шаг за шагомшаг 1 из 9 · рамок: 1

Скрипт вызывает reduce и передаёт ему колбэк add и начальное значение 0.

Каждый вызов add получает в total то, что вернул предыдущий

Начальное значение выбирают так, чтобы оно не испортило результат: для суммы это 0, для произведения — 1. reduce не меняет исходный массив.

Не только сумма

Здесь аналогия с копилкой заканчивается. В копилке лежат только деньги, а аккумулятор может хранить любое значение: максимум, счётчик, строку.

Максимум

Чтобы найти максимум, колбэк сравнивает элемент с лучшим найденным и возвращает большее из двух. Начальным значением здесь служит первый элемент.

JavaScript
const temps = [12, 31, 18];
const max = temps.reduce((best, t) => (t > best ? t : best), temps[0]);

console.log(max); // 31

Число 0 для максимума не годится. Если все числа отрицательные, результатом окажется 0, которого в массиве нет.

Счётчик

Аккумулятор бывает и счётчиком. Вызов words.reduce((count, w) => (w.length > 3 ? count + 1 : count), 0) считает слова длиннее трёх букв. Колбэк здесь возвращает либо увеличенный счётчик, либо прежний.

Без начального значения

Начальное значение можно не передавать. Тогда аккумулятором становится первый элемент, а колбэк вызывается со второго: nums.reduce((total, n) => total + n) тоже даёт 21.

Частая ошибка

Начальное значение не передали, а массив оказался пустым:

JavaScript
const empty = [];
const total = empty.reduce((sum, n) => sum + n); // ✗
TEXT
TypeError: Reduce of empty array with no initial value

Без начального значения reduce берёт аккумулятор из первого элемента, а в пустом массиве его нет. Передайте начальное значение: empty.reduce((sum, n) => sum + n, 0) возвращает 0, и колбэк не вызывается ни разу. С начальным значением reduce работает с массивом любой длины.

Главное

  • reduce собирает все элементы массива в одно значение — аккумулятор.
  • Первый вызов колбэка получает начальное значение, каждый следующий — то, что вернул предыдущий.
  • reduce возвращает результат последнего вызова и не меняет исходный массив.
  • Без начального значения reduce на пустом массиве останавливает программу с TypeError.

Подпишись, чтобы пройти курс

Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.

Войти другим способом