Array (Массив)

Array — упорядоченная коллекция элементов с числовым индексом, обеспечивающая O(1) доступ по индексу. Самая базовая и часто используемая структура данных.

Зачем нужно

Массив — фундамент программирования. Списки пользователей, товаров, сообщений, пикселей изображения — всё это массивы. Понимание внутреннего устройства помогает выбирать правильные операции и избегать O(n) там, где можно O(1).

Где используется

  • Хранение любых коллекций данных
  • Стек, очередь, буфер (реализуются на массиве)
  • Матрицы (двумерные массивы)
  • Буферы данных (TypedArray, ArrayBuffer)
  • DOM-коллекции (NodeList → Array)

Предпосылки

Массив в памяти (классический)

В языках как C, массив — непрерывный блок памяти:

Индекс:  0    1    2    3    4
Адрес:  100  104  108  112  116  (int = 4 байта)
Данные: [10] [20] [30] [40] [50]

Доступ к arr[3]: адрес = 100 + 3 × 4 = 112 → O(1)

JavaScript Array — особенности

JS-массивы — это объекты (не непрерывная память). V8 оптимизирует их в зависимости от содержимого:

// Dense array — оптимизирован как настоящий массив
const dense = [1, 2, 3, 4, 5]; // однотипные элементы, нет пропусков

// Sparse array — хранится как хэш-таблица (медленнее)
const sparse = ;
sparse[0] = 'a';
sparse[1000] = 'b'; // дырка в 999 элементов

// Смешанный — V8 может деоптимизировать
const mixed = [1, 'hello', true, { x: 1 }]; // разные типы

Создание массивов

// Литерал (рекомендуется)
const fruits = ['apple', 'banana', 'cherry'];

// Конструктор
const empty = new Array(5);        // [<5 empty slots>]
const filled = Array(5).fill(0);   // [0, 0, 0, 0, 0]

// Array.from — из итерируемого
const fromString = Array.from('hello');  // ['h', 'e', 'l', 'l', 'o']
const range = Array.from({ length: 5 }, (_, i) => i); // [0, 1, 2, 3, 4]

// Spread
const copy = [...fruits]; // поверхностная копия

// Array.of
const single = Array.of(5); // [5], а не [<5 empty>]

Операции и их сложность

Доступ и модификация

const arr = [10, 20, 30, 40, 50];

// Доступ по индексу — O(1)
arr[0];       // 10
arr[4];       // 50
arr.at(-1);   // 50 (с конца)

// Длина — O(1)
arr.length;   // 5

// Изменение по индексу — O(1)
arr[2] = 99;  // [10, 20, 99, 40, 50]

Добавление/удаление

const arr = [1, 2, 3];

// В конец — O(1) амортизированно
arr.push(4);      // [1, 2, 3, 4]

// С конца — O(1)
arr.pop();        // [1, 2, 3], вернул 4

// В начало — O(n)! Сдвигает все элементы
arr.unshift(0);   // [0, 1, 2, 3]

// С начала — O(n)! Сдвигает все элементы
arr.shift();      // [1, 2, 3], вернул 0

// Произвольная позиция — O(n)
arr.splice(1, 0, 'a');   // [1, 'a', 2, 3] — вставка
arr.splice(1, 1);        // [1, 2, 3] — удаление

Поиск

const arr = [10, 20, 30, 20, 40];

arr.indexOf(20);            // 1 (первое вхождение)    O(n)
arr.lastIndexOf(20);        // 3 (последнее)           O(n)
arr.includes(30);           // true                    O(n)
arr.find(x => x > 25);     // 30                      O(n)
arr.findIndex(x => x > 25); // 2                      O(n)

Трансформация (создают новый массив)

const nums = [1, 2, 3, 4, 5];

// map — преобразовать каждый элемент, O(n)
const doubled = nums.map(n => n * 2);     // [2, 4, 6, 8, 10]

// filter — отфильтровать, O(n)
const evens = nums.filter(n => n % 2 === 0); // [2, 4]

// reduce — свернуть в одно значение, O(n)
const sum = nums.reduce((acc, n) => acc + n, 0); // 15

// slice — вырезать часть (не мутирует), O(k)
const middle = nums.slice(1, 4);  // [2, 3, 4]

// concat — объединить, O(n+m)
const combined = nums.concat([6, 7]); // [1, 2, 3, 4, 5, 6, 7]

// flat — разворачивание, O(n)
[[1, 2], [3, [4]]].flat(Infinity); // [1, 2, 3, 4]

// flatMap — map + flat(1), O(n)
[1, 2, 3].flatMap(x => [x, x * 2]); // [1, 2, 2, 4, 3, 6]

Сортировка

const arr = [3, 1, 4, 1, 5, 9];

// sort мутирует массив! O(n log n)
arr.sort((a, b) => a - b);  // [1, 1, 3, 4, 5, 9]

// Для строк — sort без аргумента (лексикографически)
['banana', 'apple', 'cherry'].sort(); // ['apple', 'banana', 'cherry']

// toSorted — НЕ мутирует (ES2023)
const sorted = arr.toSorted((a, b) => a - b);

// toReversed, toSpliced — НЕ мутирующие версии (ES2023)
const reversed = arr.toReversed;
const spliced = arr.toSpliced(1, 1, 'new');

Таблица сложности

Операция Сложность Метод
Доступ по индексу O(1) arr[i]
Вставка в конец O(1)* push
Удаление с конца O(1) pop
Вставка в начало O(n) unshift
Удаление с начала O(n) shift
Поиск O(n) indexOf, find
Сортировка O(n log n) sort
slice O(k) slice(start, end)
splice O(n) splice

* амортизированно

Паттерны работы с массивами

// Деструктуризация
const [first, second, ...rest] = [1, 2, 3, 4, 5];
// first=1, second=2, rest=[3, 4, 5]

// Swap элементов
[arr[0], arr[1]] = [arr[1], arr[0]];

// Удаление дубликатов
const unique = [...new Set([1, 2, 2, 3, 3])]; // [1, 2, 3]

// Группировка (Object.groupBy — ES2024)
const grouped = Object.groupBy(users, user => user.role);

// Chunk — разбиение на части
function chunk(arr, size) {
  const chunks = ;
  for (let i = 0; i < arr.length; i += size) {
    chunks.push(arr.slice(i, i + size));
  }
  return chunks;
}
chunk([1, 2, 3, 4, 5], 2); // [[1, 2], [3, 4], [5]]

Частые ошибки

  1. unshift/shift в цикле. Каждый вызов — O(n), итого O(n^2). Используйте другую структуру
  2. Мутирование при итерации. Удаление элементов через splice в forEach — непредсказуемое поведение
  3. sort без компаратора для чисел. [10, 9, 1].sort()[1, 10, 9] (лексикографически!)
  4. Путать поверхностную и глубокую копию. [...arr] копирует ссылки, не вложенные объекты
// Подвох с sort
[10, 9, 1, 2, 21].sort();           // [1, 10, 2, 21, 9] — НЕПРАВИЛЬНО!
[10, 9, 1, 2, 21].sort((a, b) => a - b); // [1, 2, 9, 10, 21] — ПРАВИЛЬНО

Практика

  1. Реализуйте flatten(arr, depth) — разворачивание на заданную глубину
  2. Реализуйте chunk(arr, size) без slice
  3. Реализуйте intersection(arr1, arr2) — общие элементы двух массивов
  4. Сравните производительность push vs unshift на 100 000 элементов

Связанные темы

  • Stack (реализуется на массиве)
  • Queue (реализуется на массиве)
  • Big O нотация
  • Linked List (альтернатива для частых вставок/удалений)
  • Set (уникальные значения)

Ресурсы

  • MDN — Array
  • learn.javascript.ru — массивы
  • V8 Blog — элементы и оптимизация массивов
  • JavaScript Info — Array methods cheat sheet