Большинство разработчиков JavaScript избегают использования Array.reduce, как будто это чума, и я их не виню. Иногда это может сбивать с толку, но это не обязательно.
В большинстве учебных пособий вы узнаете, как суммировать массив чисел, и это нормально, но в реальной жизни вам, вероятно, придется иметь дело с более сложными данными.
Итак, в этом уроке я расскажу, как использовать Array.reduce, когда его использовать, и докажу вам, что Array.reduce довольно прост.
Пример 1. Суммирование чисел.
Знаю, знаю, такой классический хрестоматийный пример, но ведь надо откуда-то строить!
const arr = [1, 2, 3, 4, 5, 6, 7] const initialValue = 0 const sumFunction = (acc, current) => { return acc + current } const sum = arr.reduce(sumFunction, initialValue)
Давайте разберем это сейчас.
Мы начинаем с наших данных, которые в данном случае представляют собой массив целых чисел. Далее у нас есть начальное значение. После этого мы создаем нашу функцию суммы, которая принимает два аргумента: аккумулятор и текущее значение. Он возвращает сумму предыдущего значения и текущего значения. Наконец, мы вызываем Array.reduce с функцией суммы в качестве первого аргумента и начальным значением в качестве второго аргумента.
Когда функция суммы запускается в первый раз, аккумулятору присваивается начальное значение, которое в нашем случае равно 0. При каждом последующем запуске аккумулятор обновляется до нового значения, которое является суммой предыдущего значения и текущего значения. ценить.
Вот что происходит при каждом запуске:
Первый запуск => аккумулятор = 0
Второй запуск => аккумулятор = 0 + 1 => 1
Третий запуск => аккумулятор => 1 + 2 => 3
Четвертый прогон => аккумулятор = 3 + 3 => 6
Пятый прогон => аккумулятор = 6 + 4 => 10
Шестой запуск => аккумулятор = 10 + 5 => 15
Седьмой запуск => аккумулятор = 15 + 6 => 21
Последний запуск => аккумулятор = 21 + 7 => 28
Теперь, когда у нас есть базовое понимание, давайте углубимся в нечто более сложное.
Пример 2. Объекты
Представьте себе: мы провели большой опрос, чтобы выяснить, какие фреймворки JavaScript используются чаще всего. Колоссальные 10 000 человек ответили на наш опрос, предоставив нам длинный список результатов. Теперь нам нужно правильно организовать этот список и осмыслить всю информацию, которую мы собрали.
const bestFrameworkOrLibrary = [ 'Vanilla', "React", "React", "Angular", "Ember", "jQuery", "jQuery", "jQuery", "...." ]
Мы хотим привести список в порядок определенным образом. Нам нужно создать объект, в котором каждый фреймворк JavaScript является ключом, а значение, связанное с каждым ключом, — это количество раз, когда этот фреймворк появляется в списке. Важно отметить, что каждый фреймворк должен появляться только один раз в качестве ключа в объекте.
На помощь приходит Array.reduce.
// inital value const initialValue = {} const accumulate = (accumulator, currentItem) => { // check to see of currentItem exists in the object if (!accumulator[currentItem]) { // if it doesn't exist, let's add it and give it an initial value of 1 accumulator[currentItem] = 1 } else { // otherwise let's increment the value accumulator[currentItem] += 1 } // return our object. Always return the accumulator return accumulator } const result = bestFrameworkOrLibrary.reduce(accumulate, initialValue)
Как и прежде, у нас есть наши данные, начальное значение, функция обратного вызова и Array.reduce, который принимает наш обратный вызов и начальное значение.
Небольшая разница здесь в том, что наше начальное значение теперь является пустым объектом. Вот и все.
Наша функция обратного вызова выполняет некоторую логику, которая проверяет, существует ли currentItem (framework) в объекте, если нет, мы добавляем его и устанавливаем его значение на 1, в противном случае мы увеличиваем значение на 1.
Пример 3. Сведение массива объектов.
Скажем, у нас есть массив, который выглядит примерно так:
const data = [ { name: "Eli", hobbies: [ 'coding', 'reading', 'hiking' ] }, { name: "John", hobbies: [ 'dancing', 'reading', 'hiking' ], }, { name: "Sam", hobbies: [ 'cooking', 'swimming', 'hunting' ] } ]
Цель состоит в том, чтобы найти все уникальные хобби среди всех пользователей.
И снова на помощь приходит Array.reduce.
// inital value const initValue = [] const accum = ((acc, person) => { // loop through each person hobbies person.hobbies.forEach((hobby) => { // if hobby doesn't exist in the array, I added it to the end. if (!acc.includes(hobby)) acc.push(hobby) }) // return our accumulator return acc }) const uniqueHobbies = data.reduce(accum, initValue)
Внутри функции накопителя мы просто просматриваем список увлечений каждого человека. Мы проверяем, присутствует ли уже то или иное хобби в аккумуляторе. Если это не так, мы добавляем его в аккумулятор.
Вот в чем дело: вам не всегда нужно использовать Array.reduce. Иногда Array.filter или Array.map прекрасно справляются с этой задачей. Однако бывает ситуация, когда Array.reduce может показаться лучшим выбором, и именно тогда мы хотим оптимизировать производительность.
Допустим, вы хотите отфильтровать данные. Вы, наверное, сделали бы что-то подобное, верно?
bestFrameworkOrLibrary.filter((library) => library.endsWith("y"))
Очень верный подход.
Теперь давайте посмотрим, как мы можем сделать то же самое с Array.reduce.
bestFrameworkOrLibrary.reduce((acc, lib) => { if (lib.endsWith('y')) { acc.push(lib) } return acc }, [])
Выглядит не так уж и плохо, я думаю, у Array.filter читабельность чуть лучше, но суть не в этом.
Причина, по которой я провел это сравнение, заключалась в том, чтобы задать вам следующий вопрос: какой из них, по вашему мнению, быстрее?
Я покажу тебе!
СВЯТАЯ МАТЬ JS, фильтрация данных заняла у нас около 7,5 мс, а использование сокращения — всего 0,26 мс 😱 Array.reduce выполнил ту же задачу, но в 30 раз быстрее, чем Array. фильтр
Теперь вы можете спросить, почему такая резкая разница? Простой ответ заключается в том, что это связано со способом добавления данных в новый массив.
.push будет на несколько лет впереди по скорости, потому что все, что он делает, — это добавляет элементы в конец, где Array.filter должен перебирать весь массив, фильтровать элементы и затем создавать новый массив.
В Array.reduce все, что мы делали, это зацикливались и проталкивались до конца, вот и все, нам не нужно было ничего удалять.
В общем, Array.reduce похож на швейцарский армейский нож в JavaScript — это очень удобно!
В этой статье мы использовали его для самых разных целей: складывания чисел, подсчета голосов за любимые фреймворки JavaScript, сглаживания неуклюжего списка объектов и даже для того, чтобы обогнать Array.filter в гонке на скорость.
Конечно, поначалу Array.reduce может показаться немного сложным — например, обучение езде на велосипеде. Но как только вы освоитесь, вы увидите, как это может помочь вам работать со списками классным и эффективным способом. Это может реально изменить правила игры в некоторых случаях, когда другие методы могут оказаться не лучшими.
Но помните, как велосипед — не лучший способ пересечь океан, так и Array.reduce — не решение всех проблем. Важно подумать о том, что вы пытаетесь сделать, и выбрать лучший инструмент для работы. И, что не менее важно, убедитесь, что ваш код легко читать и понимать другим.
Итак, в следующий раз, когда вы будете программировать на JavaScript, не забывайте об Array.reduce. Это мощный инструмент, который всегда должен быть у вас в рюкзаке программиста, готовый к использованию, когда возникнет нужная проблема!