Как работает метод reduce в JavaScript
Development, Java | Комментировать запись
Сложному для понимания методу reduce посвящено много материалов в интернете, но даже такое количество информации не помогает разобраться. Метод reduce имеет много преимуществ, поскольку он часто используется в управлении состоянием.
Синтаксис метода массива reduce в JavaScript выглядит так:
arr.reduce(callback, initialValue);
Терминология
Reduce использует редуктор и аккумулятор. Аккумулятор – это значение, которым мы заканчиваем, а reducer определяет, какое действие мы будем выполнять, чтобы получить одно значение.
Вы должны помнить, что reducer возвращает только одно значение (потому функция и называется reduce).
Возьмем следующий классический пример:
const value = 0;
const numbers = [5, 10, 15];
for(let i = 0; i < numbers.length; i++) {
value += numbers[i];
}
Вышеуказанный код даст результат 30 (5 + 10 + 15). Этот код работает правильно, но мы можем сделать это вычисление с помощью reduce, что избавит нас от изменения переменной value.
Приведенный ниже код также выведет результат 30, но он не будет менять переменную value (которую мы здесь назвали initialValue).
/* this is our initial value i.e. the starting point*/
const initialValue = 0;
/* numbers array */
const numbers = [5, 10, 15];
/* reducer method that takes in the accumulator and next item */
const reducer = (accumulator, item) => {
return accumulator + item;
};
/* we give the reduce method our reducer function
and our initial value */
const total = numbers.reduce(reducer, initialValue)
Этот код может показаться немного запутанным, но внутри него не происходит никакого волшебства. Давайте добавим console.log в метод reducer, который будет выводить аргументы accumulator и item.
Вот что выводится на консоль:
accumulator is 0 item is 5
accumulator is 5 item is 10
accumulator is 15 item is 15
Итак, первое, что можно заметить – это что метод вызывается 3 раза, потому что в заданном массиве 3 значения. Аккумулятор начинается со значения 0 (оно является initialValue, которое мы передали методу reduce). При каждом вызове функции аргумент item добавляется в аккумулятор. Последний вызов метода показывает значение аккумулятора 15 и item 15, сумма которых дает нам 30, что и является окончательным значением. Помните, что метод reducer возвращает accumulator плюс item.
Это простой пример использования reduce, теперь давайте рассмотрим более сложный.
Сглаживание массива с помощью reduce
Допустим, у нас есть следующий массив:
const numArray = [1, 2, [3, 10, [11, 12]], [1, 2, [3, 4]], 5, 6];
Представим, что по какой-то необъяснимой причине JavaScript больше не поддерживает метод .flat, поэтому мы должны сгладить этот массив самостоятельно.
Давайте напишем функцию для сглаживания любого массива независимо от того, насколько глубоко он вложен:
function flattenArray(data) {
// our initial value this time is a blank array
const initialValue = [];
// call reduce on our data
return data.reduce((total, value) => {
// if the value is an array then recursively call reduce
// if the value is not an array then just concat our value
return total.concat(Array.isArray(value) ? flattenArray(value) : value);
}, initialValue);
}
Если мы передадим массив numArray этому методу и выведем результат на консоль результат, мы получим следующее:
[1, 2, 3, 10, 11, 12, 1, 2, 3, 4, 5, 6];
0: 1
1: 2
2: 3
3: 10
4: 11
5: 12
6: 1
7: 2
8: 3
9: 4
10: 5
11: 6
Этот пример показывает, как существенно упростить очень распространенную операцию.
Рассмотрим еще один пример.
Изменение структуры объекта
Итак, давайте представим, что у нас есть сервер, который отправляет нам массив объектов Pokemon, например, такой:
const pokemon = [
{ name: "charmander", type: "fire" },
{ name: "squirtle", type: "water" },
{ name: "bulbasaur", type: "grass" }
]
Нам нужно изменить объект, чтобы он выглядел так:
const pokemonModified = {
charmander: { type: "fire" },
squirtle: { type: "water" },
bulbasaur: { type: "grass" }
};
Чтобы достичь желаемого результата, мы сделаем следующее:
const getMapFromArray = data =>
data.reduce((acc, item) => {
// add object key to our object i.e. charmander: { type: 'water' }
acc[item.name] = { type: item.type };
return acc;
}, {});
Если мы вызовем наш метод:
getMapFromArray(pokemon)
мы получим нужный результат.
Заключение
На первый взгляд reduce кажется сложнее, чем другие методы итерации массивов JavaScript типа map и filter. Но если вы разберетесь в его синтаксисе, основных понятиях и случаях использования, вы получите в свой арсенал разработчика JavaScript очень мощный инструмент.
Tags: Javascript