Методы массивов в JavaScript: map, filter, reduce — понятное руководство с примерами
Запрос «map filter reduce в JavaScript» стабильно популярен: эти три метода помогают писать компактный и понятный код без лишних циклов и мутаций. Ниже — практическое руководство с примерами, рекомендациями и типичными ошибками.
Почему именно map, filter, reduce
- Декларативный стиль: вы описываете «что сделать», а не «как пройти по индексам».
- Иммутабельность: методы возвращают новый массив, исходный не меняется (кроме случаев, когда вы сами мутируете элементы-объекты).
- Композиция: их легко комбинировать в цепочки.
map: преобразование без мутаций
Метод map создаёт новый массив той же длины, применяя функцию к каждому элементу.
const prices = [100, 200, 300];
const withTax = prices.map(p => Math.round(p * 1.1));
console.log(withTax); // [110, 220, 330]
Типичная ошибка — забыть вернуть значение при использовании фигурных скобок:
const xs = [1, 2, 3];
// Плохо: нет return внутри {}
const wrong = xs.map(x => { x * 2 });
console.log(wrong); // [undefined, undefined, undefined]
// Хорошо: либо без {}, либо явно возвращаем
const ok1 = xs.map(x => x * 2);
const ok2 = xs.map(x => { return x * 2; });
Подводный камень с parseInt:
// Плохо: ['1','2','10'].map(parseInt) => [1, NaN, 2]
// Потому что parseInt(value, index) принимает индекс как основание системы счисления
const ns = ['1', '2', '10'];
const a = ns.map(parseInt);
console.log(a); // [1, NaN, 2]
// Хорошо:
const b = ns.map(s => parseInt(s, 10));
const c = ns.map(Number);
console.log(b, c); // [1, 2, 10] [1, 2, 10]
filter: отбор по условию
filter возвращает новый массив только с элементами, удовлетворяющими условию.
const users = [
{ name: 'Ann', age: 17 },
{ name: 'Bob', age: 22 },
{ name: 'Kate', age: 19 }
];
const adults = users.filter(u => u.age >= 18);
console.log(adults.map(u => u.name)); // ['Bob', 'Kate']
Удобно фильтровать «правдивые» значения:
const raw = [0, 1, '', 'hi', null, undefined, 'JS'];
const truthy = raw.filter(Boolean);
console.log(truthy); // [1, 'hi', 'JS']
Или исключать элементы по списку:
const blacklist = ['tmp', 'draft'];
const files = ['readme.md', 'tmp', 'index.js', 'draft'];
const clean = files.filter(f => !blacklist.includes(f));
console.log(clean); // ['readme.md', 'index.js']
reduce: агрегация и не только
reduce сводит массив к одному значению (числу, объекту, строке, массиву). Обязательно задавайте начальное значение — это избавит от граничных кейсов.
// Сумма
const sum = [1, 2, 3, 4].reduce((acc, x) => acc + x, 0);
console.log(sum); // 10
// Среднее
const avg = [10, 20, 30].reduce((acc, x, i, arr) => {
acc += x;
return i === arr.length - 1 ? acc / arr.length : acc;
}, 0);
console.log(avg); // 20
// Подсчёт вхождений
const words = ['a', 'b', 'a', 'c', 'b', 'a'];
const counters = words.reduce((acc, w) => {
acc[w] = (acc[w] || 0) + 1;
return acc;
}, {});
console.log(counters); // { a: 3, b: 2, c: 1 }
// Группировка по полю
const people = [
{ name: 'Ann', team: 'Blue' },
{ name: 'Bob', team: 'Red' },
{ name: 'Kate', team: 'Blue' }
];
const byTeam = people.reduce((acc, p) => {
(acc[p.team] ||= []).push(p);
return acc;
}, {});
console.log(byTeam.Blue.map(p => p.name)); // ['Ann', 'Kate']
// «Разворачивание» на один уровень (flat)
const nested = [[1, 2], [3], [4, 5]];
const flat = nested.reduce((acc, arr) => acc.concat(arr), []);
console.log(flat); // [1,2,3,4,5]
Ошибка: вызывать reduce без начального значения, особенно на пустом массиве — получите исключение или некорректный результат.
Комбинирование методов (chaining)
Часто map, filter и reduce удобно объединять. Это улучшает читаемость и позволяет выражать намерения «по шагам».
const products = [
{ name: 'Keyboard', price: 30, inStock: true },
{ name: 'Mouse', price: 15, inStock: false },
{ name: 'Monitor', price: 120, inStock: true }
];
const cheapInStockNames = products
.filter(p => p.inStock && p.price <= 50)
.map(p => p.name)
.sort();
console.log(cheapInStockNames); // ['Keyboard']
Производительность: каждая операция создаёт новый массив. В «горячих» местах можно заменить цепочку на один reduce или цикл for, но в большинстве задач выигрывает читаемость.
Практические рецепты
Уникальные значения и частоты:
const tags = ['js', 'css', 'js', 'html', 'css'];
const unique = [...new Set(tags)];
const freq = tags.reduce((acc, t) => (acc[t] = (acc[t] || 0) + 1, acc), {});
console.log(unique, freq); // ['js','css','html'] и { js: 2, css: 2, html: 1 }
Преобразование NodeList в массив и извлечение данных:
// const nodes = document.querySelectorAll('a.item');
// В средах без DOM замените nodes фиктивными данными для теста
const nodes = [{ textContent: 'A' }, { textContent: 'B' }];
const texts = Array.from(nodes).map(n => n.textContent.trim());
console.log(texts); // ['A', 'B']
Асинхронная обработка: map вернёт массив промисов. Ждите их через Promise.all.
const ids = [1, 2, 3];
const promises = ids.map(async id => {
const res = await fetch(`https://api.example.com/items/${id}`);
return res.json();
});
const items = await Promise.all(promises);
console.log(items);
Типичные ошибки
- map без return внутри фигурных скобок — получите undefined.
- parseInt в map без второго аргумента — ловушка с основанием системы счисления.
- reduce без начального значения — проблемы с пустыми массивами и типами.
- Мутация объектов внутри map: вы меняете исходные данные. Используйте копии {...obj} при необходимости.
- await внутри map без Promise.all — выполнение не будет дожидаться завершения всех операций.
Короткая шпаргалка
// map: преобразование
arr.map(x => fn(x))
// filter: отбор
arr.filter(x => condition(x))
// reduce: агрегация
arr.reduce((acc, x) => nextAcc, initial)
Что дальше изучать
Освоив «map, filter, reduce в JavaScript», имеет смысл углубиться в работу с массивами, колбэками, промисами и цепочками асинхронных операций. Если вы хотите системно прокачать навыки на практике, посмотрите программу «Прокачать JavaScript от нуля до уровня Гуру на реальных задачах». Там разобраны основы и продвинутые темы с разбором типичных ошибок.
Итог: используйте map для преобразований, filter для отбора, reduce для агрегаций и сложных трансформаций. Старайтесь писать декларативно, держать данные неизменными и не забывать про начальные значения в reduce.
-
Создано 03.11.2025 17:01:08
-
Михаил Русаков

Комментарии (0):
Для добавления комментариев надо войти в систему.
Если Вы ещё не зарегистрированы на сайте, то сначала зарегистрируйтесь.