Перейти к содержимому
Теория · Массивы · урок 7 из 13

Массив — это ссылка

Представьте дом и бумажку с его адресом. Если переписать адрес на вторую бумажку, домов не станет два: обе бумажки ведут к одному и тому же дому. Если по первой бумажке прийти и переставить мебель, то и гость со второй бумажкой увидит её на новом месте.

С числом всё иначе: присваивание b = a копирует само значение. Для массива оно работает как вторая бумажка: после b.push(3) длина a тоже выросла. А два массива с одинаковыми элементами не равны друг другу:

JavaScript
const a = [1, 2];
const b = a;
b.push(3);

console.log(a.length); // 3
console.log(a === b); // true
console.log([1, 2] === [1, 2]); // false

Давайте разберём по строкам:

  1. const a = [1, 2] создаёт массив, и a указывает на него.
  2. const b = a не создаёт второй массив: b — второе имя того же массива.
  3. b.push(3) добавляет элемент в этот единственный массив.
  4. a.length печатает 3: изменение через b видно через a.
  5. a === b даёт true: оба имени указывают на один массив.
  6. [1, 2] === [1, 2] даёт false, хотя элементы одинаковые.

Два имени одного массива

Переменная хранит не сам массив, а ссылку на него — указание, где массив лежит. Похоже на адрес дома на бумажке: b = a переписывает адрес, а дом остаётся один. В отличие от адреса, ссылку нельзя увидеть или напечатать.

Присваивание b = a копирует ссылку, и оба имени указывают на один и тот же массив. Изменение через одно имя видно через другое. const здесь не помогает: константа хранит ссылку, а не содержимое массива.

Так же массив передаётся в функцию. Параметр функции получает ссылку на тот же массив, поэтому push внутри функции изменит массив снаружи. Этот вопрос часто задают на собеседовании: «Что будет с массивом, если изменить его внутри функции?»

Нажмите «Следующий шаг» и следите за a и b: после каждого изменения у них одинаковое содержимое. Массив c — отдельная копия: его изменения не видны через a. Запись [...a], которая делает копию, разберём чуть ниже.

ВживуюДва имени одного массивашаг 1 из 10 · рамок: 1

Запись [1, 2] создаёт массив, а a получает ссылку на него.

Следите за a и b: одно изменение видно через оба имени

Сравнение массивов

Оператор === для массивов не сравнивает элементы. Он проверяет, один ли это массив, то есть одинаковые ли ссылки. Каждая запись [1, 2] создаёт новый массив, поэтому [1, 2] === [1, 2] даёт false.

Копия через три точки

Отдельную копию создаёт запись [...a]. Три точки перед массивом называют синтаксисом расширения: они раскладывают массив на отдельные элементы. Такую же копию даёт вызов slice() без аргументов.

JavaScript
const a = [3, 8, 1];
const copy = [...a];
copy.push(9);

console.log(a.length, copy.length); // 3 4
console.log(copy === a); // false
console.log([0, ...a].join(" ")); // 0 3 8 1
console.log(Math.max(...a)); // 8

В новом массиве

В записи [...a] элементы попадают в новый массив, и у копии своя ссылка. Поэтому copy.push(9) не меняет a, а copy === a даёт false. Рядом с тремя точками можно писать и другие элементы: [0, ...a] — это 0 и за ним все элементы a.

В вызове функции

Раскладывать массив тремя точками можно и в вызове функции. Math.max возвращает наибольший из своих аргументов. Вызов Math.max(...a) передаёт три числа отдельными аргументами, а Math.max(a) получил бы один массив и вернул бы NaN.

Частая ошибка

Массив проверили на пустоту сравнением с []:

JavaScript
const list = [];

if (list === []) { // ✗
    console.log("empty");
}

Ошибки нет, но программа ничего не печатает. Справа от === стоит новый пустой массив, а не list, и условие всегда ложно. Пустоту проверяют по длине: list.length === 0.

Главное

  • Переменная хранит ссылку на массив, и b = a даёт тому же массиву второе имя.
  • Функция получает ссылку на тот же массив и может его изменить.
  • === сравнивает ссылки, а не элементы, поэтому [1, 2] === [1, 2] даёт false.
  • [...a] делает отдельную копию массива с новой ссылкой.

Подпишись, чтобы пройти курс

Курс бесплатный. Войди через Telegram и подпишись на канал — откроются все уроки.

Войти другим способом