map и filter
В прошлом уроке работник у конвейера только ставил штампы, а готовые вещи никуда не попадали. Часто же из одного массива нужно получить другой: цены со скидкой или только положительные числа.
С forEach новый массив пришлось бы собирать вручную через push, ведь сам метод возвращает undefined. Представьте, что у конвейера появилась вторая лента. Работник берёт ящик с первой ленты, а на вторую кладёт то, что получилось. Так работает метод map: он сам собирает новый массив.
const prices = [10, 25, 40];
const doubled = prices.map((p) => p * 2);
console.log(doubled); // [ 20, 50, 80 ]
console.log(prices); // [ 10, 25, 40 ]Давайте разберём пример по строкам:
prices— массив из трёх цен.prices.map((p) => p * 2)вызывает колбэк для каждой цены и собирает ответы колбэка в новый массивdoubled.- Первый вызов
console.logпечатает[ 20, 50, 80 ]. - Второй печатает
[ 10, 25, 40 ]: исходный массив остался прежним.
map преобразует каждый элемент
map вызывает колбэк для каждого элемента и складывает результаты колбэка в новый массив. В новом массиве столько же элементов, сколько в исходном: один результат на каждый элемент. map не меняет сам исходный массив, поэтому prices остался прежним.
Здесь аналогия с лентами хромает. На настоящей фабрике ящик уходит с первой ленты, а массив prices после map остаётся целым, со всеми элементами на своих местах.
map подходит, когда каждому элементу нужен ровно один результат: цене — скидка, имени — заглавные буквы. Колбэк получает элемент и его индекс, как в forEach.
Возвращать колбэк может значение любого типа. Вызов ["ann", "bob"].map((name) => name.toUpperCase()) даёт массив строк ["ANN", "BOB"].
Разницу между map и forEach часто спрашивают на собеседовании. Ответ короткий: map возвращает новый массив из результатов колбэка, а forEach всегда возвращает undefined.
filter оставляет часть
Теперь у ленты стоит контролёр. Он смотрит на каждый ящик и решает: пропустить его на вторую ленту или снять. Так работает filter.
filter тоже вызывает колбэк для каждого элемента, но результат колбэка служит условием. В новый массив попадают сами элементы, для которых колбэк вернул истинное значение. Остальные отбрасываются, поэтому новый массив бывает короче исходного или вовсе пустым.
Колбэк не обязан возвращать именно true или false: его результат проверяется так же, как условие в if.
const nums = [4, 7, 10, 3];
console.log(nums.filter((n) => n > 5)); // [ 7, 10 ]
console.log(nums.filter((n) => n > 100)); // []Разберём оба вызова:
- условие
n > 5выполняется для7и10, иfilterвозвращает[ 7, 10 ]; - условие
n > 100не выполняется ни для одного числа, и результат — пустой массив[].
filter тоже не меняет исходный массив: в nums по-прежнему четыре числа.
Цепочка вызовов
map и filter возвращают массив, поэтому у результата можно сразу вызвать следующий метод. Такую запись называют цепочкой вызовов. Методы выполняются слева направо, и каждый работает с массивом, который вернул предыдущий:
const scores = [55, 90, 72, 40];
const raised = scores.filter((s) => s >= 60).map((s) => s + 5);
console.log(raised.join(" ")); // 95 77Цепочка похожа на две станции на одном конвейере. Давайте пройдём их по порядку:
filterпропускает только баллы от60, и получается[90, 72].mapприбавляет5только к этим двум числам и возвращает[95, 77].join(" ")склеивает их в строку95 77.
Порядок станций важен. Если поменять методы местами, filter проверит уже увеличенные числа.
Частая ошибка
Из массива хотели оставить чётные числа, а в условии написали только остаток:
const nums = [1, 2, 3, 4];
const evens = nums.filter((n) => n % 2); // ✗
console.log(evens);Ошибки нет, но программа выводит [ 1, 3 ]. У чётного числа остаток 0 — ложное значение, и filter такой элемент отбрасывает. У нечётного остаток 1 — истинное значение, и элемент остаётся. Сравните остаток с нулём: nums.filter((n) => n % 2 === 0) даёт [ 2, 4 ].
Главное
mapвозвращает новый массив той же длины из результатов колбэка.filterвозвращает новый массив из элементов, для которых колбэк вернул истинное значение.- Оба метода не меняют исходный массив и возвращают новый, поэтому их вызовы соединяют в цепочку.
- В отличие от
map,forEachвсегда возвращаетundefined.
Подпишись, чтобы пройти курс
Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.