Методы массивов в JavaScript: кратко и понятно, с примерами

Методы массивов в JavaScript: кратко и понятно, с примерами Полезное

В JavaScript «список» — это массив (Array), а «операторы списков» — это методы массива: встроенные функции вроде map, filter, reduce, find, push и splice, которые вызываются через точку (arr.map(...)). Кратко: одни методы меняют сам массив (добавить, удалить, отсортировать), другие возвращают новый результат, не трогая исходник (преобразовать, отфильтровать, найти, посчитать).

Ниже — шпаргалка по основным методам, один сквозной пример, методы по группам и типовые ошибки. Все примеры проверены 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?
На обычных объемах разница незаметна, а методы читаются лучше. Если массив очень большой и код в горячем пути, решает замер в вашем окружении, а не общее правило.

OTUS Журнал
Бесплатные открытые уроки (поп-ап)