</> Praktum

Главная / JavaScript / Массивы JavaScript

Урок 4 · JavaScript

Массивы: храним список значений

Редакция PraktumОбновлено 16 минут на урок с практикойУровень: новичок

Массив в JavaScript — упорядоченный список значений в квадратных скобках: ['HTML', 'CSS', 'JavaScript']. У каждого элемента есть номер — индекс, и он начинается с нуля. Свойство length хранит количество элементов, а встроенные методы добавляют, удаляют, ищут и преобразуют элементы.

Коротко
  • Индексы начинаются с 0, последний элемент — arr.at(-1).
  • push и pop работают с концом, unshift и shift — с началом.
  • map, filter, slice возвращают новый массив; push, splice, sort меняют исходный.
  • const copy = arr не копирует массив — нужен [...arr].
  • Числа сортируют с функцией: arr.sort((a, b) => a - b).

Зачем этот урок сейчас

Почти любые данные на странице — список: уроки в каталоге, товары в корзине, задачи, результаты поиска. После переменных и условий массивы — следующий шаг: без них не вывести список на страницу, не отфильтровать карточки и не сохранить задачи в localStorage.

Создание и индексы

const topics = ['HTML', 'CSS', 'JavaScript'];

console.log(topics[0]);       // 'HTML' — первый элемент
console.log(topics.length);   // 3
console.log(topics[2]);       // 'JavaScript' — последний
console.log(topics.at(-1));   // 'JavaScript' — последний короче
console.log(topics[3]);       // undefined — такого индекса нет

У массива из трёх элементов индексы 0, 1 и 2, а length равен 3. Обращение за пределы массива не вызывает ошибку, а возвращает undefined — из-за этого ошибки в индексах трудно заметить. Метод at() понимает отрицательные индексы: at(-1) — последний, at(-2) — предпоследний.

Массив может хранить что угодно: числа, строки, объекты и даже другие массивы. Но держи в одном массиве элементы одного вида — список, где перемешаны строки и объекты, неудобно сортировать и выводить.

Добавление и удаление элементов

const tasks = ['Купить хлеб'];

tasks.push('Позвонить маме');   // в конец → ['Купить хлеб', 'Позвонить маме']
tasks.unshift('Проснуться');    // в начало
tasks.pop();                    // убрать последний, вернёт его
tasks.shift();                  // убрать первый, вернёт его

const list = ['a', 'b', 'c', 'd'];
list.splice(1, 2);              // с индекса 1 убрать 2 элемента → ['a', 'd']
list.splice(1, 0, 'x');         // вставить 'x' на индекс 1 → ['a', 'x', 'd']

Массив, объявленный через const, менять можно: const запрещает только присвоить переменной другой массив. splice(start, deleteCount, ...items) — универсальный метод: удаляет, вставляет и заменяет элементы в середине.

Не удаляй элементы через delete arr[1]: на месте элемента останется дырка, а length не изменится.

Какие методы меняют массив

Методы массива
Меняют исходный массивВозвращают новый
push, pop, shift, unshiftmap, filter, slice
spliceconcat, [...a, ...b]
sort, reversetoSorted, toReversed
filltoSpliced, with

Разница важна, когда массив используется в нескольких местах. В React и Vue состояние меняют только через новые массивы, иначе интерфейс может не обновиться. Методы toSorted, toReversed, toSpliced и with появились недавно и работают в свежих браузерах.

Перебор: for...of, forEach и map

const prices = [100, 200, 300];

for (const price of prices) {
  console.log(price);
}

prices.forEach((price, index) => {
  console.log(index, price);
});

const withDiscount = prices.map((price) => price * 0.9); // [90, 180, 270]

for...of — самый понятный перебор, в нём работают break и continue. forEach делает действие для каждого элемента и ничего не возвращает. map создаёт новый массив той же длины из преобразованных значений — используй его, когда результат нужен, а не для побочных действий.

const lessons = [
  { id: 1, title: 'HTML', done: true },
  { id: 2, title: 'CSS', done: false },
];

lessons.find((l) => l.id === 2);        // { id: 2, … } или undefined
lessons.findIndex((l) => l.id === 2);   // 1 или -1
lessons.filter((l) => l.done);          // все выполненные
lessons.some((l) => !l.done);           // true — есть невыполненный
['HTML', 'CSS'].includes('CSS');        // true
['HTML', 'CSS'].indexOf('JS');          // -1
Что вернёт поиск
НужноМетод
Один элемент по условиюfind
Все подходящиеfilter
Есть ли такое значениеincludes
Есть ли элемент по условиюsome
Одно итоговое значение (сумма)reduce или цикл

Сортировка чисел и строк

[10, 1, 2].sort();                    // [1, 10, 2] — сравнил как строки!
[10, 1, 2].sort((a, b) => a - b);      // [1, 2, 10]
[10, 1, 2].sort((a, b) => b - a);      // [10, 2, 1] — по убыванию

const names = ['Ёж', 'Арбуз', 'банан'];
names.sort((a, b) => a.localeCompare(b, 'ru')); // по алфавиту с учётом русского

lessons.sort((a, b) => a.title.localeCompare(b.title)); // объекты по полю

sort без аргумента превращает элементы в строки и сравнивает посимвольно, поэтому 10 оказывается раньше 2. Функция сравнения возвращает отрицательное число, если a должен стоять раньше, и положительное — если позже. Помни, что sort меняет сам массив.

Копирование: почему const copy = arr не работает

const a = ['HTML', 'CSS'];
const b = a;          // не копия, а вторая ссылка на тот же массив
b.push('JS');
console.log(a);       // ['HTML', 'CSS', 'JS'] — изменился и a

const copy = [...a];          // поверхностная копия
const copy2 = a.slice();      // то же самое
const deep = structuredClone(lessons); // глубокая копия с вложенными объектами

Массив — объект, а переменная хранит ссылку на него. Spread и slice делают поверхностную копию: сам список новый, но объекты внутри общие. Если нужно менять вложенные объекты независимо, используй structuredClone.

Массив и строка

['HTML', 'CSS'].join(', ');   // 'HTML, CSS'
'HTML, CSS'.split(', ');      // ['HTML', 'CSS']
Array.isArray([]);            // true
typeof [];                    // 'object' — поэтому typeof не помогает

join собирает строку из элементов, split — наоборот. Проверить, что значение — массив, можно только через Array.isArray.

map или forEach

map

Нужен новый массив из преобразованных элементов: цены со скидкой, HTML-строки для вывода.

forEach

Нужно только действие для каждого элемента: вывести в консоль, добавить на страницу. Ничего не возвращает.

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

  • Ищут первый элемент по индексу 1, а не 0.
  • Пишут length() со скобками — это свойство, а не метод.
  • Сортируют числа через sort() без функции и получают 1, 10, 2.
  • Считают const copy = arr копией и случайно меняют исходный массив.
  • Используют map там, где результат никуда не сохраняется, вместо forEach или for...of.

Доступность

Когда выводишь массив на страницу, используй настоящие списки ul или ol с li: скринридер объявит «список, 5 элементов». Если список меняется без перезагрузки (добавили задачу, отфильтровали), сообщай об изменении текстом в области с aria-live.

Поддержка браузерами

Базовые методы массивов работают во всех браузерах. at(), structuredClone, findLast поддерживаются всеми актуальными браузерами. Новые неизменяющие методы toSorted, toReversed, toSpliced и with появились в 2023 году — для старых браузеров используй копию и обычный sort: [...arr].sort().

Практика

Создай массив из четырёх городов. Добавь пятый в конец, убери первый, выведи второй по счёту город и последний через at. Затем отсортируй массив по алфавиту, не меняя исходный, и собери из него строку через запятую.

Показать решение
const cities = ['Москва', 'Казань', 'Сочи', 'Тула'];
cities.push('Омск');
cities.shift();
console.log(cities[1]);      // 'Сочи'
console.log(cities.at(-1));  // 'Омск'

const sorted = [...cities].sort((a, b) => a.localeCompare(b, 'ru'));
console.log(sorted.join(', '));

Открыть песочницу

Частые вопросы

Почему первый элемент массива имеет индекс 0?

Индекс — это смещение от начала массива. У первого элемента смещение ноль. Так устроено в большинстве языков программирования.

Как получить последний элемент массива?

arr.at(-1) или по-старому arr[arr.length - 1].

Как удалить элемент из массива по значению?

Новым массивом: arr.filter((x) => x !== value). Или найди индекс через indexOf и удали splice(index, 1) — это изменит исходный массив.

Почему sort неправильно сортирует числа?

Без функции сравнения sort сравнивает элементы как строки. Передай (a, b) => a - b.

Как скопировать массив?

[...arr] или arr.slice() — поверхностная копия. Для вложенных объектов — structuredClone(arr).

Источники