В JavaScript «список» — это массив (Array), а «операторы списков» — это методы массива: встроенные функции вроде map, filter, reduce, find, push и splice, которые вызываются через точку (arr.map(...)). Кратко: одни методы меняют сам массив (добавить, удалить, отсортировать), другие возвращают новый результат, не трогая исходник (преобразовать, отфильтровать, найти, посчитать).
Содержание
- Три слова, без которых методы не объяснить
- Шпаргалка: что делает метод и что возвращает
- Один пример: map, filter, reduce и find вместе
- Добавить и удалить: push, pop, shift, unshift, splice
- Преобразовать и свернуть: map, filter, reduce, flatMap
- Найти и проверить: find, includes, some, every
- Частые ошибки: неверно -> результат -> как исправить
- Как выбрать метод под задачу
- Выводы
- Где применяется / связь с практикой
- FAQ
Ниже — шпаргалка по основным методам, один сквозной пример, методы по группам и типовые ошибки. Все примеры проверены 24.09.2026 в Node.js 24.21 (актуальная LTS); в современных браузерах работают так же.
Три слова, без которых методы не объяснить
- Колбэк — функция, которую вы передаете в метод; метод сам вызывает ее для каждого элемента:
arr.map((item) => item * 2). Обычно колбэк получает три аргумента: элемент, индекс, весь массив. - Мутирующий метод — изменяет исходный массив (
push,splice,sort,reverse). После вызова старого содержимого уже нет. - Возвращаемое значение — то, что метод отдает обратно. У
mapэто новый массив, уfind— один элемент, уpush— новая длина массива (а не сам массив), уforEach— всегдаundefined.
Путаница «почему в переменной число, а не массив» почти всегда из-за третьего пункта.
Шпаргалка: что делает метод и что возвращает
| Метод | Что делает | Возвращает | Меняет исходный? |
|---|---|---|---|
push(x) / pop() |
добавить в конец / убрать последний | новую длину / убранный элемент | да |
unshift(x) / shift() |
добавить в начало / убрать первый | новую длину / убранный элемент | да |
splice(i, n, ...) |
удалить n элементов с индекса i и вставить новые |
массив удаленных | да |
slice(a, b) |
вырезать кусок [a, b) |
новый массив | нет |
map(fn) |
преобразовать каждый элемент | новый массив той же длины | нет |
filter(fn) |
оставить элементы, для которых fn вернул истинное значение |
новый массив | нет |
reduce(fn, init) |
свернуть массив в одно значение | одно значение (число, объект, массив) | нет |
find(fn) / findIndex(fn) |
найти первый подходящий | элемент или undefined / индекс или -1 |
нет |
some(fn) / every(fn) |
есть ли хоть один / все ли подходят | true или false |
нет |
includes(x) / indexOf(x) |
есть ли значение / где оно | true/false / индекс или -1 |
нет |
sort(fn) / reverse() |
отсортировать / развернуть | тот же массив | да |
forEach(fn) |
выполнить действие для каждого | undefined |
сам нет |
Упрощение: колонка «меняет исходный?» говорит о самом методе. Если колбэк внутри map или forEach меняет поля объектов (task.done = true), объекты изменятся и в исходном массиве: новый массив от map, filter или slice хранит ссылки на те же объекты (поверхностная копия), а forEach вообще ничего не копирует.
Один пример: map, filter, reduce и find вместе
Список задач на день, из которого нужно получить названия, выполненные задачи, потраченное на них время и первую длинную задачу.
const tasks = [
{ name: "Написать отчет", minutes: 120, done: true },
{ name: "Созвон с командой", minutes: 30, done: false },
{ name: "Ревью кода", minutes: 45, done: true },
{ name: "Почистить почту", minutes: 15, done: false },
];
const names = tasks.map((task) => task.name);
const doneTasks = tasks.filter((task) => task.done);
const doneMinutes = doneTasks.reduce((sum, task) => sum + task.minutes, 0);
const firstLong = tasks.find((task) => task.minutes > 40);
console.log(names);
console.log(doneTasks.length, "задачи выполнено");
console.log("На выполненные ушло", doneMinutes, "мин");
console.log(firstLong.name);
console.log(tasks.length); // исходный массив не изменился
Вывод в консоли Node.js:
[
'Написать отчет',
'Созвон с командой',
'Ревью кода',
'Почистить почту'
]
2 задачи выполнено
На выполненные ушло 165 мин
Написать отчет
4
Разбор по строкам:
mapпрошел по всем четырем задачам и из каждой взялname— получился массив строк той же длины.filterоставил только объекты, гдеdoneистинно, — их два.reduceначал с0(второй аргумент) и на каждом шаге прибавлялminutes: 0 + 120 + 45 = 165.findостановился на первой задаче длиннее 40 минут и вернул сам объект, а не массив.tasksостался прежним: ни один из четырех методов его не меняет.
Тот же результат можно получить циклом for, но пришлось бы заводить пустой массив, счетчик и следить за индексами. Методы короче и сразу называют намерение: «преобразовать», «отобрать», «посчитать», «найти».
Добавить и удалить: push, pop, shift, unshift, splice
Эти методы меняют массив на месте. Обратите внимание на возвращаемые значения в комментариях.
const list = ["a", "b", "c"];
console.log(list.push("d")); // 4 - новая длина
console.log(list.pop()); // "d"
console.log(list.unshift("z")); // 4
console.log(list.shift()); // "z"
console.log(list); // [ 'a', 'b', 'c' ]
const letters = ["a", "b", "c", "d", "e"];
const removed = letters.splice(1, 2); // с индекса 1 удалить 2
console.log(removed, letters); // [ 'b', 'c' ] [ 'a', 'd', 'e' ]
letters.splice(1, 0, "X", "Y"); // вставить, ничего не удаляя
console.log(letters); // [ 'a', 'X', 'Y', 'd', 'e' ]
const part = letters.slice(1, 3); // копия с 1 по 3 (не включая)
console.log(part, letters); // [ 'X', 'Y' ] [ 'a', 'X', 'Y', 'd', 'e' ]
splice и slice путают чаще всего. Мнемоника: у splice есть лишняя буква «p», и он «портит» исходный массив; slice только делает копию куска.
Если исходник трогать нельзя (например, это состояние компонента в React), есть копирующие версии мутирующих методов из стандарта ES2023: toSpliced, toSorted, toReversed и with(i, value).
const base = [3, 1, 2];
const copy = base.toSpliced(0, 1);
console.log(copy, base); // [ 1, 2 ] [ 3, 1, 2 ]
console.log(base.with(0, 99), base); // [ 99, 1, 2 ] [ 3, 1, 2 ]
Они есть в Node.js 20+ и в актуальных версиях браузеров; в старом окружении их не будет, там используют копию через [...arr] и обычный метод.
Преобразовать и свернуть: map, filter, reduce, flatMap
map — «было N элементов, стало N других». Длина всегда та же.
filter — «было N, осталось столько, сколько прошло проверку». Колбэк возвращает условие; значение приводится к логическому, поэтому false, 0, "", null, undefined и NaN считаются ложью.
reduce — «было N, стало одно значение». Колбэк получает аккумулятор (результат прошлого шага) и текущий элемент и обязан вернуть новый аккумулятор. Одно значение не обязательно число — это может быть объект. Пример: посчитать, сколько раз встречается каждое слово.
const words = ["кот", "пес", "кот", "еж", "кот"];
const counts = words.reduce((acc, w) => {
acc[w] = (acc[w] ?? 0) + 1;
return acc;
}, {});
console.log(counts); // { 'кот': 3, 'пес': 1, 'еж': 1 }
Для вложенных массивов есть flat (сделать один уровень плоским) и flatMap (сначала map, потом flat):
const nested = [ [1, 2], [3], [4, 5] ];
console.log(nested.flat()); // [ 1, 2, 3, 4, 5 ]
console.log(["a b", "c"].flatMap((s) => s.split(" "))); // [ 'a', 'b', 'c' ]
Найти и проверить: find, includes, some, every
findнужен, когда ищем по условию и хотим сам элемент;findIndex— его позицию;findLast— последний подходящий.includesотвечает только «есть или нет» для конкретного значения.some— «хотя бы один подходит»,every— «подходят все».
console.log([1, 2, 3].find((n) => n > 5), [1, 2, 3].findIndex((n) => n > 5)); // undefined -1
console.log([3, 8, 12].some((n) => n > 10), [3, 8, 12].every((n) => n > 1)); // true true
console.log([5, 12, 8, 130].findLast((n) => n > 10)); // 130
console.log([NaN].indexOf(NaN), [NaN].includes(NaN)); // -1 true
Последняя строка — граница indexOf: он сравнивает строгим равенством, а NaN не равен сам себе, поэтому indexOf его не находит. includes использует другое сравнение (SameValueZero) и находит. Объекты оба метода ищут по ссылке, а не по содержимому: для поиска объекта по полю нужен find.
Частые ошибки: неверно -> результат -> как исправить
1. Фигурные скобки в map без return.
const nums = [1, 2, 3];
const bad = nums.map((n) => { n * 2; });
console.log(bad); // [ undefined, undefined, undefined ]
const good = nums.map((n) => n * 2);
console.log(good); // [ 2, 4, 6 ]
Стрелочная функция с { } — это тело, и без return она возвращает undefined. Ошибки не будет, просто тихо получится массив из undefined. Исправление: убрать скобки или написать return n * 2;. Та же ошибка в filter дает пустой массив.
2. reduce на пустом массиве без начального значения.
try { [].reduce((a, b) => a + b); } catch (e) { console.log(e.name + ": " + e.message); }
// TypeError: Reduce of empty array with no initial value
console.log([].reduce((a, b) => a + b, 0)); // 0
Без второго аргумента reduce берет первый элемент как стартовый аккумулятор, а на пустом массиве брать нечего. Исправление: всегда передавать начальное значение (0 для суммы, {} для подсчета, [] для сборки массива).
3. sort без функции сравнения сортирует числа как строки.
const prices = [100, 25, 3, 1000];
console.log(prices.sort()); // [ 100, 1000, 25, 3 ]
console.log(prices.sort((a, b) => a - b)); // [ 3, 25, 100, 1000 ]
const orig = [100, 25, 3, 1000];
console.log(orig.toSorted((a, b) => b - a), orig); // [ 1000, 100, 25, 3 ] [ 100, 25, 3, 1000 ]
По умолчанию sort приводит элементы к строкам и сравнивает посимвольно, поэтому "1000" оказывается раньше "25". Исправление: функция (a, b) => a - b (по возрастанию) или b - a (по убыванию). Заодно помните: sort меняет исходный массив, а toSorted — нет.
4. Ждать результат от forEach.
const r = [1, 2, 3].forEach((n) => n * 2);
console.log(r); // undefined
forEach ничего не собирает, он только выполняет действие. Если нужен новый массив — это map. Кроме того, из forEach нельзя выйти досрочно через break: для перебора с остановкой берут for...of, find или some.
Как выбрать метод под задачу
| Задача | Метод |
|---|---|
| Получить новый массив той же длины | map |
| Отобрать часть элементов | filter |
| Посчитать сумму, собрать объект, сгруппировать | reduce |
| Найти один элемент по условию | find (позиция — findIndex) |
| Проверить наличие значения | includes |
| Проверить условие для одного / для всех | some / every |
| Добавить или убрать с краю | push, pop, unshift, shift |
| Удалить или вставить в середине | splice (без изменения исходника — toSpliced) |
| Отсортировать | sort с функцией сравнения (копией — toSorted) |
| Просто выполнить действие для каждого | forEach или for...of |
Выводы
- Список в JavaScript — это массив, а «операторы списков» — методы массива, вызываемые через точку.
- Главное различие: мутирующие методы (
push,splice,sort) меняют исходный массив, остальные (map,filter,reduce,find,slice) возвращают новый результат. map— та же длина,filter— часть элементов,reduce— одно значение,find— один элемент илиundefined.- Типовые ловушки: нет
returnв колбэке с фигурными скобками,reduceбез начального значения,sortбез функции сравнения, ожидание результата отforEach.
Где применяется / связь с практикой
Освойте тему на практике
Методы массивов — повседневный инструмент фронтенда и Node.js: вывести список товаров из ответа API (map), отфильтровать по цене (filter), посчитать сумму корзины (reduce), найти пользователя по id (find). Чтобы закрепить их на задачах с проверкой наставником, подойдет курс «JavaScript-разработчик. Базовый уровень». Разобрать отдельные темы вживую можно на бесплатных открытых уроках Otus.
FAQ
Работают ли методы массивов на NodeList или строке?
Не все: у NodeList есть forEach, но нет map и filter, у строки нет map, filter и forEach (свои slice, includes, indexOf у нее есть, но это методы строки). Преобразуйте в массив через Array.from(x) или [...x], а потом вызывайте нужный метод.
Можно ли передать в map асинхронную функцию?
Можно, но результатом будет массив промисов, а не значений. Чтобы дождаться всех, оберните его в await Promise.all(arr.map(async (x) => ...)).
Что быстрее: цикл for или map/filter?
На обычных объемах разница незаметна, а методы читаются лучше. Если массив очень большой и код в горячем пути, решает замер в вашем окружении, а не общее правило.



