Массивы в JavaScript: основы, методы и примеры кода
Массивный гайд для быстрого погружения.
В программировании часто нужно хранить набор значений в одном месте и обращаться к ним по порядку. Для этого в JavaScript используют массивы (Array) — специальный тип объекта для работы с упорядоченными коллекциями данных. В этой статье мы подробно поговорим про массивы, и вы узнаете, как их создавать и использовать. Кроме того, в конце вас ждут несколько несложных задач, с помощью которых вы сможете закрепить изученный материал.
Содержание
- Что такое массивы в JavaScript и как их создавать
- Что такое length и как обращаться к элементам массива
- Как перебрать массив в JavaScript
- Как добавлять и удалять элементы массива
- Основные методы массивов в JavaScript
- Что такое вложенные массивы и как с ними работать
- Как проверить равенство массивов в JavaScript
- Типичные ошибки при работе с массивами
- Задачи для закрепления теории
Что такое массивы в JavaScript и как их создавать
Массив (Array) в JavaScript — это упорядоченная коллекция элементов, где каждый элемент имеет свой числовой индекс (позицию). Индексация начинается с 0: первый элемент находится по индексу arr[0], второй — arr[1] и так далее. В отличие от многих других языков программирования, массивы в JS могут содержать элементы разных типов: числа, строки, логические значения true или false, объекты, функции и даже другие массивы.
Представьте, что вы хотите сохранить список покупок. Вместо того чтобы создавать переменные для каждого товара, можно использовать массив.
// Без массива неудобно
const item1 = 'молоко';
const item2 = 'хлеб';
const item3 = 'яйца';
// С массивом удобно и компактно
const shoppingList = ['молоко', 'хлеб', 'яйца'];
console.log(shoppingList); // ['молоко', 'хлеб', 'яйца']
// Можно легко добавить новый товар
shoppingList.push('масло');
console.log(shoppingList); // ['молоко', 'хлеб', 'яйца', 'масло']В JavaScript есть несколько способов создать массив. Самый простой — через квадратные скобки []. Это называется литералом массива. Пустые скобки создают пустой массив, а если добавить внутрь какие-то данные — получится массив с элементами.
// Пустой массив
const arr = [];
console.log(arr); // []
// Массив из трёх строк
const animals = ['cat', 'dog', 'mouse'];
console.log(animals); // ['cat', 'dog', 'mouse']Есть и другой способ создать массив — вызвать конструктор Array (обычно через new Array(…)). Здесь важно помнить, что у него два режима работы: если передать одно число, оно будет воспринято как длина массива, и элементы при этом не заполняются значением undefined — создаются пустые слоты; а если передать несколько значений, они станут элементами массива — например, new Array(1, 2, 3) создаст массив из трёх чисел.
// Массив из трёх пустых элементов
const emptyArray = new Array(3);
console.log(emptyArray); // [empty × 3]
// Массив из перечисленных элементов
const numsArray = new Array(1, 2, 3);
console.log(numsArray); // [1, 2, 3]Кроме литерала [] и конструктора Array() есть методы Array.of() и Array.from(). Они помогают создавать массивы и преобразовывать другие значения в массивы.
Метод Array.of() создаёт массив из всех переданных значений. Он работает предсказуемее, чем Array():
const objs = Array.of(3, 'c', 'dfds');
console.log(objs); // [3, 'c', 'dfds']Метод Array.from() преобразует строку и другие итерируемые значения в массив. Если вторым аргументом передать функцию, она сразу обработает каждый элемент.
// Превращаем строку в массив символов
const charArr = Array.from('hello');
console.log(charArr); // ['h', 'e', 'l', 'l', 'o']
// Превращаем каждый символ строки в массив чисел
const numArr = Array.from('12345', Number);
console.log(numArr); // [1, 2, 3, 4, 5]
Читайте также:
Что такое length и как обращаться к элементам массива
Массив хранит элементы по порядку, и у каждого свой номер — индекс. Нумерация начинается с нуля: первый элемент находится под индексом 0, второй — под индексом 1 и так далее.
const items = ['item01', 'item02', 'item03'];
console.log(items[0]); // item01Если вы попытаетесь обратиться к несуществующему индексу, JavaScript вернёт undefined. Это означает, что элемента с таким индексом в массиве нет. Важно понимать, что отрицательных индексов у массивов в JavaScript не существует в том смысле, в котором они есть, например, в Python. Поэтому запись items[-1] не вернёт последний элемент, а будет воспринята как обращение к свойству объекта с ключом -1. Соответственно, если такого свойства у массива нет (а по умолчанию его нет), результат всегда будет undefined.
// Отрицательный индекс
console.log(items[-1]); // undefined
// Несуществующий индекс
console.log(items[999]); // undefinedСвойство length возвращает количество элементов в массиве.
const array = ['objFirst', 'obj2', 'obj3', 'objLast'];
console.log(array.length); // 4Это свойство удобно использовать для получения последнего элемента. Индексация начинается с 0, поэтому последний элемент всегда будет иметь индекс на единицу меньше длины массива.
console.log(array[array.length - 1]); // objLastМассивы в JavaScript можно расширять или уменьшать — их размер не фиксирован. Если вы вручную измените length, то массив подстроится под новое значение.
При увеличении длины в массиве появятся пустые слоты (empty slots) — они существуют формально, но не содержат значений. При обращении к ним вы получите undefined.
const arrayLength = [1, 2, 3];
arrayLength.length = 5;
console.log(arrayLength); // [1, 2, 3, empty × 2]
console.log(arrayLength[4]); // undefinedПри уменьшении длины массив обрезается, и все элементы с индексами больше или равными новому значению length будут безвозвратно удалены:
const truncatedArray = [1, 2, 3, 4, 5];
truncatedArray.length = 3;
console.log(truncatedArray); // [1, 2, 3]Как перебрать массив в JavaScript
Чтобы выполнить действие для каждого элемента массива — например, вывести значения в консоль, обработать данные или изменить элементы, — используют перебор (итерацию). В JavaScript для этого есть несколько способов: классический цикл for, современный for…of и метод forEach(). Рассмотрим каждый на примере следующего массива:
const numbers = ['Один', 'Два', 'Три', 'Четыре', 'Пять'];Цикл for
Цикл for начинается с индекса первого элемента и далее на каждой итерации увеличивает счётчик i на единицу, пока не достигнет значения length массива. Условие i < numbers.length определяет момент остановки. Этот способ даёт полный контроль: вы можете начать с любого индекса, изменить шаг итерации и даже перебирать массив в обратном порядке.
for (let i = 0; i < numbers.length; i++) {
console.log(numbers[i]);
}
/*
Один
Два
Три
Четыре
Пять
*/Цикл for…of
Этот цикл перебирает значения массива напрямую — без счётчика и без необходимости обращаться к элементам по индексу. Для его использования достаточно указать массив, объявить переменную для хранения текущего элемента и использовать ключевое слово of:
for (const item of numbers) {
console.log(item);
}
/*
Один
Два
Три
Четыре
Пять
*/Метод forEach()
forEach() — встроенный метод массива, который перебирает элементы по порядку и для каждого вызывает переданную функцию обратного вызова (callback). JavaScript автоматически передаёт в эту функцию три аргумента: текущий элемент, его индекс и ссылку на весь массив.
Сам по себе метод forEach() не изменяет исходный массив, однако внутри callback-функции вы можете явно модифицировать элементы через индекс или другие методы, если это требуется.
numbers.forEach((item, index) => {
console.log(`${index}: ${item}`);
});
/*
0: Один
1: Два
2: Три
3: Четыре
4: Пять
*/Как добавлять и удалять элементы массива
В JavaScript есть четыре основных метода для добавления и удаления элементов массива: unshift() добавляет элемент в начало, push() — в конец, shift() удаляет первый элемент, а pop() — последний. Эти методы изменяют исходный массив и не создают новый.
const elements = ['element01', 'element02'];
console.log(elements); // ['element01', 'element02']
// Добавляем элемент в начало массива
elements.unshift('newElementAtStart');
console.log(elements); // ['newElementAtStart', 'element01', 'element02']
// Добавляем элемент в конец массива
elements.push('newElementAtEnd');
console.log(elements); // ['newElementAtStart', 'element01', 'element02', 'newElementAtEnd']
// Удаляем первый элемент массива
elements.shift();
console.log(elements); // ['element01', 'element02', 'newElementAtEnd']
// Удаляем последний элемент массива
elements.pop();
console.log(elements); // ['element01', 'element02']Методы shift() и pop() не только удаляют элементы из массива, но и возвращают удалённое значение. Это позволяет сохранить его в переменную и использовать дальше.
const elements2 = ['element01', 'element02', 'element03'];
const first = elements2.shift();
console.log(first); // element01
console.log(elements2); // ['element02', 'element03']
const last = elements2.pop();
console.log(last); // element03
console.log(elements2); // ['element02']Основные методы массивов в JavaScript
Помимо методов добавления и удаления элементов, в JavaScript есть и другие инструменты для работы с массивами. Для удобства разделим их на две группы: методы, которые изменяют исходный массив (мутирующие), и методы, которые возвращают новый массив или значение.
Это далеко не полный перечень, но именно с этими методами мы рекомендуем познакомиться каждому новичку в первую очередь. Они достаточно просты и встречаются во многих задачах.
Методы, которые меняют исходный массив
splice(start, deleteCount, …items) — удаляет указанное количество элементов, начиная с позиции start, и при необходимости вставляет новые элементы на их место. Если вы не укажете deleteCount, то будут удалены все элементы от start и до конца массива.
const modifyArr = [1, 2, 3, 4];
modifyArr.splice(1, 2, 99); // Удаляем два элемента, начиная с индекса 1, и вставляем число 99
console.log(modifyArr); // [1, 99, 4]sort() — меняет порядок элементов массива. По умолчанию этот метод преобразует элементы в строки и сравнивает их посимвольно. Из-за этого числа могут отсортироваться неправильно. Чтобы этого избежать, нужно передать функцию сравнения: (a, b) => a — b для сортировки по возрастанию или (a, b) => b — a — по убыванию.
const sortNums = [10, 2, 1];
sortNums.sort((a, b) => a - b); // Сортируем элементы по возрастанию
console.log(sortNums); // [1, 2, 10]reverse() — переворачивает массив, меняя порядок элементов на обратный.
const reverseArr = [1, 2, 3];
reverseArr.reverse();
console.log(reverseArr); // [3, 2, 1]Методы, которые возвращают новый массив или значение
slice(start, end) — возвращает новый массив, который содержит копию элементов исходного массива от индекса start (включительно) до индекса end (не включая его).
const originalArray = [1, 2, 3, 4];
const part = originalArray.slice(1, 3);
console.log(part); // [2, 3]concat() — объединяет два или более массива и возвращает новый общий массив.
const firstPart = [1, 2];
const secondPart = [3, 4];
const merged = firstPart.concat(secondPart);
console.log(merged); // [1, 2, 3, 4]join(separator) — объединяет все элементы массива в одну строку, вставляя между ними указанный разделитель. Если разделитель не указан, по умолчанию метод использует запятую.
const letters = ['a', 'b', 'c'];
const joined = letters.join('-');
console.log(joined); // "a-b-c"map() — применяет переданную функцию к каждому элементу исходного массива и создаёт новый массив с результатами полученных преобразований.
const baseNumbers = [1, 2, 3];
const doubled = baseNumbers.map((n) => n * 2);
console.log(doubled); // [2, 4, 6]filter() — возвращает новый массив с элементами исходного массива, для которых переданная функция вернула true. Например, можно выбрать только чётные числа.
const filterSource = [1, 2, 3, 4];
const even = filterSource.filter((n) => n % 2 === 0);
console.log(even); // [2, 4]find() — возвращает первый элемент, который соответствует заданному условию, или undefined, если ничего не найдено. Для примера мы можем найти число больше единицы.
const searchSource = [1, 2, 3, 4, 5];
const found = searchSource.find((n) => n > 1);
console.log(found); // 2includes() — проверяет, содержится ли определённый элемент в выбранном массиве.
const checkSource = [1, 2, 3];
const hasTwo = checkSource.includes(2);
console.log(hasTwo); // trueЧто такое вложенные массивы и как с ними работать
Иногда одного массива недостаточно, и вам нужно представить данные в виде таблицы, описать координаты на плоскости или сохранить несколько списков в одной структуре. В таких случаях используют вложенные массивы — массивы, элементы которых сами являются массивами.
Начнём с двумерного массива. Его удобно представлять как таблицу из строк и столбцов.
const matrix = [
[1, 2, 3],
[4, 5, 6]
];
// Выводим массив табличным видом в консоль
console.table(matrix);
/*
┌─────────┬───┬───┬───┐
│ (index) │ 0 │ 1 │ 2 │
├─────────┼───┼───┼───┤
│ 0 │ 1 │ 2 │ 3 │
│ 1 │ 4 │ 5 │ 6 │
└─────────┴───┴───┴───┘
*/Чтобы получить элемент из вложенного массива, необходимо указать два индекса: сначала номер строки (вложенного массива), затем номер столбца (элемента внутри него).
// Обращаемся к элементам двумерного массива
console.log(matrix[0][2]); // 3 (первая строка, третий элемент)
console.log(matrix[1][0]); // 4 (вторая строка, первый элемент)Массивы в JavaScript могут быть вложены друг в друга на любое количество уровней. Степень вложенности называется глубиной массива. Одномерный массив (например, [1, 2, 3]) имеет глубину «один». Двумерный массив — тот, что мы создали выше, — имеет глубину «два». Трёхмерный массив, соответственно, — глубину «три», и так далее. Однако вы должны помнить: чем больше вложенность, тем сложнее работать с такими структурами. Код становится менее читаемым, а обращение к элементам требует больше индексов и увеличивает риск ошибок.
Для примера создадим трёхмерный массив и обратимся к последнему элементу. А теперь представьте, что вложенность будет намного больше, и как это усложнит работу с массивом.
const cube = [
[[1, 2], [3, 4]],
[[5, 6], [7, 8]]
];
// Выводим трёхмерный массив в консоль
console.table(cube);
/*
┌─────────┬──────────┬──────────┐
│ (index) │ 0 │ 1 │
├─────────┼──────────┼──────────┤
│ 0 │ [ 1, 2 ] │ [ 3, 4 ] │
│ 1 │ [ 5, 6 ] │ [ 7, 8 ] │
└─────────┴──────────┴──────────┘
*/
// Получаем доступ к элементу в трёхмерном массиве
console.log(cube[1][1][1]); // 8
/*
cube[1] — второй блок [[5, 6], [7, 8]]
cube[1][1] — вторая строка [7, 8]
cube[1][1][1] — второй элемент «8»
*/Как проверить равенство массивов в JavaScript
Массив в JavaScript — это объект, а объекты в JavaScript сравниваются по ссылке, а не по содержимому. Операторы == и === проверяют не данные внутри массива, а то, ссылаются ли обе переменные на один и тот же объект в памяти. Поэтому, даже если два массива содержат одинаковые элементы в том же порядке, сравнение вернёт false, если это разные объекты.
const arrayOne = [1, 2];
const arrayTwo = [1, 2];
// Хотя содержимое одинаковое, это разные объекты в памяти
console.log(arrayOne === arrayTwo); // falseРавенство становится возможным только тогда, когда обе переменные указывают на один и тот же массив в памяти. В этом случае нет двух отдельных массивов — есть один объект-массив и две ссылки (переменные), которые указывают на него. Именно поэтому оператор === возвращает true: сравниваются не значения, а адреса в памяти, и они совпадают.
const listA = [1, 2, 3];
const listB = listA; // Две переменные указывают на один и тот же массив в памяти
console.log(listA === listB); // trueЕсли нужно сравнить содержимое массивов (а не ссылки), в JavaScript для этого нет готового оператора или метода. Поэтому сравнение обычно делают вручную: сначала проверяют длину, затем сравнивают элементы по индексам. Если хотя бы один элемент отличается, массивы считаются разными. Один из простых и читабельных вариантов — через метод every():
const arraysEqual = (a, b) => a.length === b.length && a.every((value, i) => value === b[i]);
const firstList = [1, 2, 3];
const secondList = [1, 2, 3];
const thirdList = [1, 2, 4];
console.log(arraysEqual(firstList, secondList)); // true
console.log(arraysEqual(firstList, thirdList)); // falseОднако имейте в виду: такой код корректно работает только для массивов с простыми значениями — числами, строками, логическими типами. Он не универсален и не подходит для глубокого сравнения вложенных структур, но для базовых случаев его можно использовать.
Типичные ошибки при работе с массивами
В JavaScript существует множество методов для работы с массивами, и при их использовании неизбежно возникают нюансы. Однако мы заметили, что ошибки часто появляются не из-за «сложных» методов, а из-за мелочей: неверной проверки типа, попыток обратиться к несуществующим элементам, ошибок в переборе и прочего. В этом разделе мы собрали самые частые промахи, которые встречаются у новичков, и показываем, как их избежать.
Проверка типа массива с помощью typeof
При работе с массивами вы можете случайно попытаться определить их тип с помощью оператора typeof. Однако в JS массивы реализованы как особый вид объектов, поэтому typeof возвращает object. Этот оператор не различает обычные объекты и массивы.
const checkTypeArray = [];
console.log(typeof checkTypeArray); // "object"Для проверки используйте метод Array.isArray(), который принимает значение и возвращает true, если это массив, и false — если нет.
console.log(Array.isArray(checkTypeArray)); // trueОбращение к элементам с помощью отрицательных индексов
Некоторые разработчики, знакомые с другими языками вроде Python, предполагают, что отрицательный индекс обращается к элементам с конца массива. В JavaScript это не работает: отрицательное значение воспринимается не как индекс элемента, а как имя свойства объекта. А поскольку такого свойства у массива нет, результатом будет undefined.
const fruitList = ["яблоко", "груша"];
console.log(fruitList[-1]); // undefinedЧтобы получить элемент с конца массива, используйте метод at().
console.log(fruitList.at(-1)); // грушаПрямое изменение свойства length
Свойство length можно изменять напрямую, и иногда его используют для очистки массива, присваивая length = 0. С технической точки зрения это допустимо, но важно понимать: изменение length модифицирует сам массив, а не создаёт новый. Поэтому если этот массив используется в других частях программы, изменение length затронет все эти места.
Чтобы избежать неожиданных побочных эффектов и сохранить исходные данные в безопасности, мы рекомендуем перед изменением массива создать его копию. Например, используйте spread-оператор (…), который создаёт поверхностную копию массива:
const numericSeries = [1, 2, 3];
const backupSeries = [...numericSeries]; // Создаём копию перед очисткой
numericSeries.length = 0; // Очищаем массив
console.log(numericSeries); // []
console.log(backupSeries); // [1, 2, 3] (копия осталась)Неправильное условие завершения цикла
Эта ошибка возникает при переборе массива циклом for, когда в условии используется <= вместо <. В результате цикл выполняет на шаг больше положенного и обращается к элементу с индексом, равным length. А поскольку такого индекса нет, в конце выводится undefined.
const iterationItems = [1, 2, 3];
console.log("Цикл с ошибкой (<=):");
for (let i = 0; i <= iterationItems.length; i++) {
console.log(iterationItems[i]); // undefined
}Добавляем строгое сравнение в условии — и всё в порядке.
console.log("Верный цикл (<):");
for (let i = 0; i < iterationItems.length; i++) {
console.log(iterationItems[i]);
}
/*
1
2
3
*/Игнорирование мутабельности массивов
Когда вы передаёте массив в функцию, туда попадает не копия, а ссылка на тот же самый объект в памяти. Это значит, что любые изменения массива внутри функции напрямую затрагивают исходный массив. Например, если функция добавляет новый элемент через метод push(), этот элемент появится и в исходном массиве за пределами функции.
const modifyInPlace = (arr) => {
arr.push("новый элемент");
};
const sourceList = [1, 2, 3];
modifyInPlace(sourceList);
console.log(sourceList); // [1, 2, 3, "новый элемент"]Если по логике программы вам не нужно изменять исходный массив, безопаснее работать с его копией и возвращать новый результат. Это хорошая практика, поскольку так вы избегаете побочных эффектов, когда один и тот же массив может использоваться в разных местах кода.
const modifyWithCopy = (arr) => {
const copy = [...arr];
copy.push("ещё один элемент");
return copy;
};
const originalList = [1, 2, 3];
const updatedList = modifyWithCopy(originalList);
console.log(originalList); // [1, 2, 3] (оригинал не изменился)
console.log(updatedList); // [1, 2, 3, "ещё один элемент"]Задачи для закрепления теории
Закрепим знания и разберём несколько простых задач на работу с массивами. Если вам нужно больше практики, рекомендуем зарегистрироваться на платформе Codewars и решать по одной задаче в день. Регулярная практика поможет вам быстрее освоить синтаксис, научиться применять методы массивов в реальных ситуациях и развить алгоритмическое мышление.
Задача 1. Подсчёт элементов массива
Предположим, у нас есть массив чисел, и нам нужно посчитать количество положительных, отрицательных и нулевых элементов.
const taskNumbers = [-5, 0, 3, -8, 12, 0, -2];Решение
Создадим переменные-счётчики для каждого типа значений и пройдём по массиву циклом for of.
let positiveCount = 0;
let negativeCount = 0;
let zeroCount = 0;
for (const num of taskNumbers) {
if (num > 0) {
positiveCount++;
} else if (num < 0) {
negativeCount++;
} else {
zeroCount++;
}
}
console.log({ positiveCount, negativeCount, zeroCount });
// { positiveCount: 2, negativeCount: 3, zeroCount: 2 }Задача 2. Пересчёт цен со скидкой
У вас есть массив с ценами, которые нельзя менять. Вам нужно получить новый массив со скидкой 15%, но убрать из результата товары, которые после скидки стоят меньше 100.
const productPrices = [
100, 150, 80, 200, 50, 300, 120, 90, 450, 60,
1000, 15, 250, 500, 75, 130, 800, 40, 110, 600
];Решение
Сначала с помощью метода map() мы проходим по исходному массиву и для каждой цены вычисляем новую — получается новый массив значений. Затем применяем filter() к этому массиву и оставляем только те цены, которые после скидки составляют не менее 100.
const discountedPrices = productPrices.map((price) => price * 0.85);
const finalPrices = discountedPrices.filter((price) => price >= 100);
console.log(finalPrices);
// [ 127.5, 170, 255, 102, 382.5, 850, 212.5, 425, 110.5, 680, 510 ]Задача 3. Очистка и форматирование списка гостей
Предположим, у вас есть массив имён гостей из формы на сайте. В нём есть лишние пробелы и пустые строки. Вам нужно очистить данные, оставить только имена и собрать их в одну строку.
const rawNames = [
" Алексей ", " ", "мария ", " С ", " Игорь",
"ольга", " Пётр ", "Елена ", " ", "александр",
"Дмитрий", "светлана", " И ", "нИкИтА", " Анна ",
" Борис", " катЯ ", " ", "владимир", "артём"
];Решение
Чтобы решить эту задачу, вам необходимо последовательно обработать массив с помощью изученных в этой статье методов, а также некоторых методов строк. Строковые методы в JS вы должны были изучить перед тем, как изучать массивы.
Вот порядок действий:
- очистите строки от пробелов методом trim() через map();
- удалите короткие значения через filter(), проверяя свойство length;
- приведите имена к правильному регистру через map(), используя методы toUpperCase() и toLowerCase();
- добавьте приставку «Гость» через map();
В завершение объедините всё в строку методом join() и выведите результат.
// Убираем лишние пробелы по краям каждого имени
const trimmedNames = rawNames.map((name) => name.trim());
// Оставляем только те имена, где больше одного символа
const validNames = trimmedNames.filter((name) => name.length > 1);
// Исправляем регистр: первая буква заглавная, остальные строчные
const capitalizedNames = validNames.map((name) => {
return name[0].toUpperCase() + name.slice(1).toLowerCase();
});
// Добавляем к каждому имени приставку «Гость»
const guestNames = capitalizedNames.map((name) => `Гость: ${name}`);
// Собираем всё в одну строку с разделителем ", "
const guestListString = guestNames.join(", ");
console.log(guestListString);
// Гость: Алексей, Гость: Мария, Гость: Игорь, Гость: Ольга, Гость: Пётр, Гость: Елена, Гость: Александр, Гость: Дмитрий, Гость: Светлана, Гость: Никита, Гость: Анна, Гость: Борис, Гость: Катя, Гость: Владимир, Гость: АртёмБольше интересного про код — в нашем телеграм-канале. Подписывайтесь!