☕ map(), filter() и reduce() в JavaScript
Код на JavaScript можно сделать более функциональным, попутно облегчив труд программиста. Знакомимся с методами массивов map(), filter() и reduce().
Перевод публикуется с сокращениями, автор оригинальной статьи Aditya Dhanraj Tiwari.
Методы массивов map, filter и reduce – по сути, лишь некоторые из наиболее известных и простых в использовании функций высшего порядка, которые обеспечивают обратный вызов для каждого элемента. В этой статье мы рассмотрим, как применение map(), filter() и reduce() поможет сделать код:
- понятным;
- менее подверженным побочным эффектам, т. к. эти методы не изменяют массив, а создают новый;
- избегающим явных циклов.
Приступим к рассмотрению.
Array.map()
Представим ситуацию, в которой есть несколько записей для студентов с атрибутами: name, ID и marks.
Постановка задачи: получить имена студентов и записать их заглавными буквами.
Ожидаемый результат:
Существует несколько способов достижения цели:
Во всех вышеупомянутых примерах создается пустой массив для хранения результата. Как в for(...of)
, так и в for()
нужно явно перебирать
массивы, что делает код более запутанным.
Решение с помощью map()
Приведенный выше фрагмент кода показывает, насколько лаконичным становится синтаксис, когда используется метод map и не нужно определять пустой массив.
Работа map():
Метод map() принимает два аргумента: функцию обратного вызова и необязательное значение объекта.
Обратный вызов map() выполняется для каждого элемента исходного массива и возвращает новое значение в результирующий.
Если thisValue не задано, функция обратного вызова будет привязана к объекту, который ее вызвал (это значение зависит от выражения вызывающего объекта). В нашем примере thisValue будет привязываться к studentRecords.
Array.filter()
filter() возвращает только те элементы из массива, которые удовлетворяют заданным критериям.
Постановка задачи: предположим, что у нас есть тот же набор данных, что и выше, но на этот раз мы хотим получить подробную информацию о студентах, набравших более 50 баллов.
Ожидаемый результат:
Решение: используем filter() для выбора записей, удовлетворяющих заданному условию (т. е. больше 50 баллов).
Постановка задачи: получить информацию о студентах, набравших более 50 баллов и имеющих id больше 120.
Решение: как показано в приведенном выше фрагменте кода, используя filter() с несколькими условиями для фильтрации данных, мы можем эффективно справиться с задачей.
Работа filter():
filter() принимает функцию обратного вызова, которая возвращает значение bool. Если она возвращает true, то объект добавляется в результирующий массив. В противном случае объект игнорируется.
Array.reduce()
Точно так же, как map() и filter(), reduce() выполняет обратный вызов для каждого элемента массива. Чтобы лучше понять reduce, сначала нужно рассмотреть два термина: «accumulator» и «reducer».
Accumulator – это значение, которое мы получаем в конечном итоге, а reducer – действие, которое следует выполнить для его получения. Важно помнить, что reducer всегда будет возвращать только одно значение.
Постановка задачи: на этот раз необходимо знать общую сумму баллов студентов.
Решение:
Работа reduce():
Давайте разберемся в работе reducer шаг за шагом:
- reduce() принимает accumulator, текущее значение, выражение и initialValue в качестве параметра, используемого для инициализации accumulator (обратите внимание, что в нашем примере initialValue = 0);
- reduce() принимает первый элемент массива в качестве текущего значения и accumulator, а затем выполняет требуемую операцию (как при сложении двух значений в нашем примере) и сохраняет результат в accumulator;
- Затем accumulator заменяется ранее рассчитанным accumulator, и текущее значение устанавливается на второй элемент массива. Необходимая операция выполняется и accumulator обновляется с новым результатом.
- Шаг 3 выполняется, пока все элементы массива не будут перебраны.
- Метод возвращает значение accumulator.
Чтобы сравнить наши знания с фактической работой reduce(), рассмотрим значения «accumulator» и «curr_value» для каждой итерации из приведенного выше примера.
Из журнала видно, что accumulator начинается со значения 0 и на каждом шаге его значение обновляется суммой «previous value» и «curr_value».
Теперь объединим возможности map(), filter() и reduce()
Пример 1. map() и filter()
Постановка задачи: на этот раз мы хотим получить только имена студентов, набравших более 50 баллов из того же набора данных.
Решение: сначала мы отфильтровали данные с помощью filter(), а затем использовали map(), чтобы получить только атрибут name.
Примечание: Вы можете связать map() и filter(), так как они возвращают массивы.
Пример 2. filter() и reduce()
Постановка задачи: напечатаем сумму баллов студентов с id больше 120.
Решение: сначала выбрали студентов с идентификатором больше 120 с помощью filter(), а потом передали отфильтрованный массив студентов в reduce(), чтобы получить сумму их баллов.
Примечание: вы можете связать reduce() после map() и filter(), поскольку они возвращают массивы, но не можете связать map() и filter() после reduce(), т. к. он возвращает единственное значение.
Пример 3. map(), filter() и reduce()
Постановка задачи: вывести общее количество студентов с баллами больше 50, полученными после начисления поощрения в 15 баллов.
Решение:
- Используя map(), добавляется поощрение в 15 баллов студентам, набравшим менее 50 баллов.
- Затем, используем filter() для массива студентов, возвращаемого функцией map(). Так мы найдем всех студентов с отметками больше 50.
- Наконец, мы использовали функцию reduce() для возвращаемого функцией filter() массива студентов, чтобы вернуть сумму оценок.
Заключение
В этом гайде мы разобрались, как map(), filter() и reduce() могут облегчить жизнь разработчику, сократив количество ненужных явных циклов и объявлений пустых массивов. Это сделает код более функциональным и легким для понимания. Попробуйте заменять циклы этими методами всякий раз, когда у вас появится такая возможность. Удачи!
Дополнительные материалы:
- Прощай, плохой код: вот как не лажать в JavaScript
- Разбираем на примерах: как избежать мутаций в JavaScript
- Учи JavaScript правильно. Путеводитель для растерявшихся
- Всегда чистый код: 5 инструментов для JavaScript-разработчика
- Где JavaScript джуну получать тестовые задания для практики?