меню

Работа с массивами — базовая и ежедневная задача для JS-разработчика. Понимание нюансов каждого метода, включая их стоимость и побочные эффекты, напрямую влияет на производительность и надежность кода. Давайте структурируем знания, выходя за рамки простого перечисления.

Мутирующие методы (Mutating Methods)

Эти методы изменяют исходный массив. Важно помнить об этом, чтобы избежать непреднамеренных сайд-эффектов.

push(...items) / unshift(...items)

Добавляют элементы в конец/начало. Возвращают новую длину массива.

	
const arr = [1, 2];
const newLength = arr.push(3); // arr = [1, 2, 3], newLength = 3		
	

Примечание:

  • unshift добавляет все аргументы сразу, а не по одному. Они становятся частью массива в том порядке, в котором переданы.

    			
    arr.unshift(0, -1); // arr = [-1, 0, 1, 2, 3]
    			
    		
  • Критически важно: unshift — дорогой оператор для больших массивов, так как он требует сдвига всех существующих элементов и пересчета их индексов. push работает значительно быстрее, так как просто добавляет элементы в конец.

pop() / shift()

Удаляют и возвращают последний/первый элемент. Если массив пуст, возвращают undefined.

	
const last = arr.pop(); // last = 3, arr = [-1, 0, 1, 2]
const first = arr.shift(); // first = -1, arr = [0, 1, 2]
	

Примечание:

Аналогично unshift, метод shift требует сдвига всех элементов, начиная с индекса 1, влево, что делает его затратным для больших массивов. pop — быстрый.

splice(start[, deleteCount, ...items])

"Швейцарский нож" для работы с массивами. Изменяет массив, начиная с индекса start, удаляя deleteCount элементов и вставляя ...items на их место. Возвращает массив удаленных элементов.

	
const arr = ['a', 'b', 'c', 'd'];
const removed = arr.splice(1, 2, 'X', 'Y');
// arr = ['a', 'X', 'Y', 'd']
// removed = ['b', 'c']
	

Примечание:

  • Отрицательный start отсчитывается с конца.
  • Если deleteCount опущен, удаляет все элементы до конца.
  • Можно использовать для вставки без удаления: arr.splice(2, 0, 'Z');
  • Производительность: Это мутирующий метод, который может быть затратным, так как после точки вставки/удаления требует сдвига оставшихся элементов и пересчета их индексов.

sort([compareFunction])

Сортирует массив на месте. Без функции сравнения преобразует элементы в строки и сортирует лексикографически.

	
const nums = [10, 2, 1];
nums.sort(); // [1, 10, 2] - сюрприз!
nums.sort((a, b) => a - b); // [1, 2, 10] - правильно для чисел
	

Примечание:

  • Для сложных структур используйте явную compareFunction.

    			
    const users = [{name: 'Bob', age: 30}, {name: 'Alice', age: 25}];
    users.sort((a, b) => a.age - b.age); // Сортировка по возрасту
    			
    		
  • Стабильность: Начиная с ES2019, метод sort в JavaScript является стабильным. Это означает, что элементы, сравнение которых приводит к равенству, сохраняют свой исходный относительный порядок.
  • Производительность: Эффективность алгоритма сортировки зависит от браузера (движка), но в большинстве случаев используется высокооптимизированный алгоритм (Timsort в V8).

reverse() / fill(value[, start[, end]])

reverse переворачивает массив. fill заполняет массив одним значением от start до end (не включая).

	
const arr = [1, 2, 3];
arr.fill(0, 1); // [1, 0, 0]
arr.reverse(); // [0, 0, 1]
	

Примечание:

fill отлично подходит для инициализации массивов фиксированной длины.

	
const newArray = new Array(5).fill(0); // [0, 0, 0, 0, 0]
	

Не мутирующие методы (Non-Mutating Methods)

Создают новый массив или возвращают новое значение, не трогая исходный.

concat(...items)

Объединяет массивы. Принимает как массивы, так и простые значения.

	
const arr1 = [1, 2];
const arr2 = [3, 4];
const newArr = arr1.concat(arr2, 5); // [1, 2, 3, 4, 5]
// arr1 и arr2 не изменены
	

Примечание:

В современном JS часто заменяется на Spread Operator:

	
const newArr = [...arr1, ...arr2, 5]; // Аналогичный результат
	

Однако concat может быть чуть более производительным при объединении именно двух массивов, в то время как spread syntax более читаем и универсален.

slice([start[, end]])

Возвращает новый массив, содержащий копию элементов от start до end (не включая). Отрицательные индексы работают с конца.

	
const arr = [10, 20, 30, 40];
const subArr = arr.slice(1, 3); // [20, 30]
const copy = arr.slice(); // Поверхностная копия массива
	

Примечание:

Создает поверхностную копию (shallow copy). Если массив содержит объекты, они не будут клонированы, и в новом массиве будут ссылки на те же объекты.

join([separator])

Склеивает элементы в строку. separator по умолчанию - запятая.

	
['2024', '12', '31'].join('-'); // "2024-12-31"
	

indexOf(item[, from]) / lastIndexOf() / includes(item[, from])

Поиск в массиве. indexOf и lastIndexOf возвращают индекс (или -1), includes — булево значение.

	
const arr = [1, 2, 3, 2, 1];
arr.indexOf(2); // 1
arr.lastIndexOf(2); // 3
arr.includes(4); // false
	

Примечание:

  • Для поиска объектов или NaN эти методы не подходят (используйте find).

    			
    [NaN].indexOf(NaN); // -1 (не находит)
    [NaN].includes(NaN); // true (находит)
    			
    		
  • includes правильно обрабатывает NaN, в отличие от indexOf.
  • Используют строгое сравнение (===).

find(predicate) / findIndex(predicate)

Ищут элемент/индекс с помощью функции-предиката. Возвращают первый удовлетворяющий элемент или его индекс.

	
const users = [{id: 1}, {id: 2}, {id: 1}];
const user = users.find(item => item.id === 1); // {id: 1}
const index = users.findIndex(item => item.id === 1); // 0
	

Примечание:

Предикат-функция вызывается для каждого элемента до тех пор, пока не будет найдено совпадение. Это может быть эффективнее filter, если нужен только первый элемент.

Итерационные методы (Iteration Methods)

Основа функционального программирования в JS. Не меняют исходный массив (кроме forEach, который может изменять элементы, если они мутабельны).

forEach(callback)

Просто выполняет функцию для каждого элемента. Возвращает undefined.

	
['a', 'b', 'c'].forEach((letter, index) => {
    console.log(`${index}: ${letter}`);
});
	

Примечание:

  • Нельзя прервать цикл break или return из колбэка. Для досрочного прерывания используйте обычный for или for..of.
  • В отличие от for, не создает отдельную область видимости для блока, если используется стрелочная функция.

map(callback)

Создает новый массив, применяя функцию к каждому элементу. Размер итогового массива всегда равен исходному.

	
const nums = [1, 2, 3];
const doubled = nums.map(n => n * 2); // [2, 4, 6]
	

Примечание:

Всегда возвращает новый массив. Исходный массив не изменяется. Это один из самых часто используемых и полезных методов.

filter(callback)

Создает новый массив со всеми элементами, прошедшими проверку (предикат вернул true).

	
const nums = [1, 2, 3, 4, 5];
const even = nums.filter(n => n % 2 === 0); // [2, 4]
	

Примечание:

Если ни один элемент не подошел, возвращает пустой массив.

reduce(callback[, initialValue]) / reduceRight

Сворачивает массив в одно значение. callback(accumulator, currentItem, index, array).

	
const sum = [1, 2, 3, 4].reduce((acc, curr) => acc + curr, 0); // 10
	

Примечание:

Всегда передавайте initialValue для надежности. Без нее:

  1. acc берется как первый элемент массива.
  2. Итерация стартует со второго элемента.
  3. Вызов на пустом массиве без initialValue выбросит TypeError.

some(callback) / every(callback)

Проверяют, удовлетворяет ли хотя бы один (some) или все (every) элементы условию. Имеют ленивое выполнение (short-circuit).

	
const hasNegative = [1, -2, 3].some(n => n < 0); // true (остановится на -2)
const allPositive = [1, 2, 3].every(n => n > 0); // true
	

Новые методы (ES6+)

flat([depth]) / flatMap(callback)

flat "поднимает" вложенные массивы на указанный depth (по умолчанию 1). flatMap эквивалентен map().flat(1), но более эффективен.

	
const arr = [1, [2, [3]]];
arr.flat(); // [1, 2, [3]]
arr.flat(2); // [1, 2, 3]

const phrases = ['hello world', 'goodbye moon'];
const words = phrases.flatMap(phrase => phrase.split(' '));
// ['hello', 'world', 'goodbye', 'moon']
	

Примечание:

flatMap позволяет отфильтровать элементы на этапе маппинга, возвращая пустой массив для нежелательных элементов.

	
const arr = [1, 2, 3, 4];
const result = arr.flatMap(x => x % 2 === 0 ? [] : [x * 2]);
// [2, 6] (удвоили только нечетные, отфильтровав четные)
	

Array.from(iterable[, mapFn])

Создает массив из массивоподобного или итерируемого объекта (например, NodeList, arguments, String, Set).

	
Array.from('foo'); // ['f', 'o', 'o']
Array.from([1, 2, 3], x => x * x); // [1, 4, 9] // Использование mapFn
	

Примечание:

Второй аргумент mapFn позволяет сначала создать массив, а затем сразу его обработать, что часто эффективнее цепочки Array.from().map().

Array.isArray(value)

Надежная проверка, является ли значение массивом (в отличие от typeof, который для массива возвращает 'object').

	
Array.isArray([]); // true
Array.isArray({}); // false
Array.isArray(Array.prototype); // true (да, это тоже массив!)
	

Заключение

Правильный выбор метода массива — это не только вопрос синтаксиса, но и:

  1. Производительности: Понимание стоимости операций (например, unshift/shift vs push/pop) критично для работы с большими данными.
  2. Иммутабельности: Использование не мутирующих методов делает код предсказуемее, особенно в реактивных фреймворках (React, Vue).
  3. Читаемости: Цепочка map().filter().reduce() часто яснее, чем один большой цикл for, и меньше подвержена ошибкам.

Комбинируйте эти методы, осознавая их внутреннюю работу, чтобы создавать не только мощные и выразительные, но и высокопроизводительные конструкции для обработки данных.

Помощь сайту
ЮMoney:
4100 1180 7209 833
Карта Сбербанк:
2202 2080 6183 7127

Возможно, вам будет интересно

Чистый код на JavaScript, 5 рекомендаций которые улучшат Ваш код.

Написание хорошо переиспользуемого кода иногда может быть сложным. Мы можем программировать на разных языках и придерживаться определенных ограничений или шаблонов, которые несут смысл от конкретного контекста.

Обработка ошибок в JavaScript. 10 примеров использования конструкции try...catch

Как фронтенд-разработчики мы часто используем try...catch в JavaScript для обработки ошибок. В этой статье я поделюсь десятью полезными советами, которые помогут вам более уверенно работать с исключениями.

Семь необходимых операторов RxJS

Как front-end разработчик вы знаете, что управление асинхронными данными - это не легкая задача. Иногда кажется, что нужна целая команда клоунов, чтобы держать все эти мячи в воздухе! Но в этом и заключается сила библиотеки RxJS. Она помогает легко манипулировать потоками асинхронных данных.

Методы массивов в JavaScript: Исчерпывающий гид для разработчиков

Работа с массивами — базовая и ежедневная задача для JS-разработчика. Понимание нюансов каждого метода, включая их стоимость и побочные эффекты, напрямую влияет на производительность и надежность кода.