Массивы

Массив — упорядоченная коллекция элементов с числовыми индексами, начиная с 0.

Зачем нужно

Массивы — основная структура для хранения списков: пользователи, товары, сообщения. Методы массивов (map, filter, reduce) — ключ к функциональному стилю программирования.

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

  • Списки данных из API
  • DOM-коллекции
  • Обработка и трансформация данных
  • Очереди и стеки
  • Аргументы функций

Предпосылки

Объекты, Циклы

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

// Литерал (основной способ)
const fruits = ['яблоко', 'банан', 'вишня'];

// new Array
const empty = new Array(3);       // [, , ,] — 3 пустых слота
const filled = new Array(1, 2, 3); // [1, 2, 3]

// Array.of — без подвоха с одним аргументом
Array.of(3);      // [3] (не 3 пустых!)
Array.of(1, 2, 3); // [1, 2, 3]

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

// Spread
const copy = [...fruits];

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

const arr = ['a', 'b', 'c', 'd', 'e'];

// Чтение
arr[0];      // 'a'
arr.at(-1);  // 'e' (ES2022, с конца)
arr.at(-2);  // 'd'

// Запись
arr[1] = 'B';
arr[10] = 'z'; // Создаёт «дыры» — arr.length станет 11

// Длина
arr.length;   // количество элементов
arr.length = 2; // Обрезает массив до ['a', 'B']

Методы мутирующие (изменяют оригинал)

const arr = [1, 2, 3];

// Добавление/удаление с конца
arr.push(4);      // [1, 2, 3, 4] — возвращает новую длину
arr.pop();        // [1, 2, 3] — возвращает удалённый элемент

// Добавление/удаление с начала
arr.unshift(0);   // [0, 1, 2, 3] — возвращает новую длину
arr.shift();      // [1, 2, 3] — возвращает удалённый элемент

// splice — универсальный: удаление, вставка, замена
const items = ['a', 'b', 'c', 'd', 'e'];
items.splice(1, 2);           // удалить 2 элемента с индекса 1 → ['a', 'd', 'e']
items.splice(1, 0, 'x', 'y'); // вставить на индекс 1 → ['a', 'x', 'y', 'd', 'e']
items.splice(0, 1, 'A');      // заменить первый → ['A', 'x', 'y', 'd', 'e']

// Сортировка
[3, 1, 2].sort();                     // [1, 2, 3]
['банан', 'яблоко', 'вишня'].sort();  // по алфавиту
[10, 2, 30].sort();                   // [10, 2, 30] — строковая!
[10, 2, 30].sort((a, b) => a - b);    // [2, 10, 30] — числовая

// reverse
[1, 2, 3].reverse(); // [3, 2, 1]

// fill
new Array(5).fill(0);  // [0, 0, 0, 0, 0]
[1, 2, 3].fill('x', 1, 2); // [1, 'x', 3]

Методы НЕмутирующие (возвращают новый массив)

map — трансформация каждого элемента

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

const users = [{ name: 'Алиса' }, { name: 'Боб' }];
const names = users.map(u => u.name);
// ['Алиса', 'Боб']

filter — отбор по условию

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

const adults = users.filter(u => u.age >= 18);

reduce — свёртка в одно значение

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

// Сумма
const sum = numbers.reduce((acc, n) => acc + n, 0); // 15

// Подсчёт вхождений
const words = ['да', 'нет', 'да', 'да', 'нет'];
const count = words.reduce((acc, word) => {
  acc[word] = (acc[word] || 0) + 1;
  return acc;
}, {});
// { да: 3, нет: 2 }

// Группировка
const people = [
  { name: 'Алиса', dept: 'IT' },
  { name: 'Боб', dept: 'HR' },
  { name: 'Чарли', dept: 'IT' }
];
const grouped = people.reduce((acc, person) => {
  (acc[person.dept] ??= ).push(person);
  return acc;
}, {});

find / findIndex / findLast

const users = [
  { id: 1, name: 'Алиса' },
  { id: 2, name: 'Боб' },
  { id: 3, name: 'Чарли' }
];

users.find(u => u.id === 2);       // { id: 2, name: 'Боб' }
users.findIndex(u => u.id === 2);  // 1
users.find(u => u.id === 99);      // undefined
users.findLast(u => u.id < 3);    // { id: 2, name: 'Боб' } (ES2023)

slice — подмассив

const arr = [0, 1, 2, 3, 4];
arr.slice(1, 3);  // [1, 2]
arr.slice(-2);    // [3, 4]
arr.slice;      // [0, 1, 2, 3, 4] — поверхностная копия

concat, flat, flatMap

[1, 2].concat([3, 4]); // [1, 2, 3, 4]
[1, [2, [3]]].flat();    // [1, 2, [3]]
[1, [2, [3]]].flat(Infinity); // [1, 2, 3]

// flatMap = map + flat(1)
['Привет мир', 'Как дела'].flatMap(s => s.split(' '));
// ['Привет', 'мир', 'Как', 'дела']

Новые иммутабельные методы (ES2023)

const arr = [3, 1, 2];

arr.toSorted((a, b) => a - b);  // [1, 2, 3] — arr не изменён
arr.toReversed;                 // [2, 1, 3] — arr не изменён
arr.toSpliced(1, 1, 99);        // [3, 99, 2] — arr не изменён
arr.with(0, 'X');                 // ['X', 1, 2] — arr не изменён

Проверки

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

arr.includes(3);               // true
arr.some(n => n > 4);          // true (хотя бы один)
arr.every(n => n > 0);         // true (все)
Array.isArray(arr);            // true
Array.isArray('not array');    // false

Перебор

const arr = ['a', 'b', 'c'];

// forEach — без возвращаемого значения
arr.forEach((item, index) => {
  console.log(`${index}: ${item}`);
});

// for...of — рекомендуется
for (const item of arr) {
  console.log(item);
}

// for...of с индексом
for (const [index, item] of arr.entries()) {
  console.log(`${index}: ${item}`);
}

// Классический for — когда нужен контроль
for (let i = 0; i < arr.length; i++) {
  console.log(arr[i]);
}

Деструктуризация массивов

const [first, second, ...rest] = [1, 2, 3, 4, 5];
// first = 1, second = 2, rest = [3, 4, 5]

// Пропуск элементов
const [, , third] = [1, 2, 3]; // third = 3

// Значения по умолчанию
const [a = 10, b = 20] = [1];
// a = 1, b = 20

// Обмен переменных
let x = 1, y = 2;
[x, y] = [y, x]; // x = 2, y = 1

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

1. sort сортирует как строки

[10, 2, 30].sort();              // [10, 2, 30] — неправильно!
[10, 2, 30].sort((a, b) => a - b); // [2, 10, 30] — правильно

2. forEach не поддерживает break/return

// forEach нельзя прервать
[1, 2, 3].forEach(n => {
  if (n === 2) return; // Пропустит только текущую итерацию!
});

// Используй for...of для break
for (const n of [1, 2, 3]) {
  if (n === 2) break; // Работает
}

3. Мутация в map/filter

// map должен возвращать новое значение, не мутировать
const users = [{ name: 'Алиса', active: false }];
// Плохо:
users.map(u => { u.active = true; return u; }); // мутирует оригинал
// Хорошо:
users.map(u => ({ ...u, active: true })); // новый объект

Практика

  1. Напиши функцию unique(arr) — удаляет дубликаты
  2. Напиши chunk(arr, size) — разбивает массив на группы
  3. Используй reduce для подсчёта суммы цен товаров
  4. Отсортируй массив объектов по нескольким полям

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

Ресурсы