Как работает метод reduce в JavaScript

Сложному для понимания методу 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:

Добавить комментарий