Урок 4 · JavaScript
Массивы: храним список значений
Массив в 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, unshift | map, filter, slice |
splice | concat, [...a, ...b] |
sort, reverse | toSorted, toReversed |
fill | toSpliced, 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
Нужен новый массив из преобразованных элементов: цены со скидкой, HTML-строки для вывода.
Нужно только действие для каждого элемента: вывести в консоль, добавить на страницу. Ничего не возвращает.
Частые ошибки
- Ищут первый элемент по индексу 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).