Что такое map, filter и reduce в JavaScript и в чем их отличие
Что проверяют
Базовое владение массивами, но на деле интервьюера интересуют граничные случаи и понимание иммутабельности. Следом часто просят реализовать map через reduce или объяснить, почему ['1', '2', '3'].map(parseInt) даёт странный результат.
Как отвечать
Все три метода принимают колбэк с аргументами (element, index, array) и не меняют исходный массив:
map: возвращает новый массив той же длины, где каждый элемент это результат колбэка. Используется для преобразования, в React это основной способ отрисовать список сkey;filter: возвращает новый массив из элементов, для которых колбэк вернул truthy значение. Длина от нуля до исходной. В React через него удаляют элемент из состояния без мутации;reduce: сворачивает массив в одно значение любого типа через аккумулятор:(acc, item) => ..., второй аргумент задаёт начальное значение. Подходит для сумм, подсчётов, построения объекта по ключу.
Главное отличие в том, что возвращается: массив той же длины, подмножество или произвольное значение. Из reduce можно выразить оба других метода, но читаемость от этого страдает.
Дальше покажите глубину:
- без начального значения
reduceберёт первый элемент как аккумулятор и начинает со второго, а на пустом массиве бросаетTypeError; - цепочка
filter().map()создаёт промежуточный массив. На обычных объёмах это неважно, на сотнях тысяч элементов лучше один проход. В ES2025 появились iterator helpers:values().filter().map()работает лениво, без промежуточных массивов; - иммутабельность поверхностная: если колбэк меняет поля объектов, исходные объекты тоже изменятся;
- для группировки вместо
reduceтеперь естьObject.groupBy.
Где спотыкаются
Пишут стрелочную функцию с фигурными скобками и без return: arr.map(x => { x * 2 }) возвращает массив из undefined.
Не могут объяснить parseInt в map: индекс уходит вторым аргументом как основание системы счисления, и получается [1, NaN, NaN].
Передают в filter асинхронный колбэк. Он возвращает промис, а промис всегда truthy, поэтому фильтр пропускает все элементы. Сначала await Promise.all с проверками, потом синхронный filter.