Дан массив:
const arr = [1,2,3,4,5]
arr.push(0) повлияет на массив так же, как если бы мы выполнили:
Теория: массив, индексы, length
С точки зрения языка массив — это объект со свойствами, где “числовые индексы” являются особыми именами свойств, а length автоматически согласуется с наибольшим индексом.
Значение length — неотрицательное целое, и оно всегда численно больше наибольшего индекса, который реально присутствует в массиве.
length изменяется не “по количеству присвоений”, а по правилу: если установлено значение по индексу, который больше либо равен текущему length, то length увеличивается, чтобы быть больше этого индекса.Схема для const arr = [1,2,3,4,5] (до изменений):
индекс: 0 1 2 3 4
знач.: 1 2 3 4 5
length: 5
Разбор каждого варианта
Сравнение удобно делать по двум критериям: какой элемент меняется и меняется ли length.
Для исходного массива arr.length равно 5, значит “конец массива” в терминах индекса — это позиция 5 (следующая после 4).
Таблица эффектов (исходно arr = [1,2,3,4,5], length = 5):
| Операция | Что меняется | Новый массив (видимая часть) | Новый length |
|---|---|---|---|
arr.push(0) | Добавляется элемент по следующему индексу в конце | [1,2,3,4,5,0] | 6 |
arr[0] = 0 | Перезаписывается первый элемент | [0,2,3,4,5] | 5 |
arr[arr.length] = 0 | Создаётся элемент по индексу 5 (так как length был 5) | [1,2,3,4,5,0] | 6 |
arr[arr.length - 1] = 0 | Перезаписывается индекс 4 | [1,2,3,4,0] | 5 |
arr[-1] = 0 | Создаётся свойство с ключом "-1" (не индекс массива) | [1,2,3,4,5] и доп. свойство | 5 |
Почему вариант 2 эквивалентен:
- При
arr[arr.length] = 0сначала вычисляется текущееarr.length(это 5), затем выполняется присваиваниеarr[5] = 0, и так как индекс 5 находится “за концом”,lengthстановится 6. pushделает именно добавление в конец и обновляетlength(плюс возвращает новую длину как значение выражения).
Почему вариант 4 не эквивалентен:
- “Отрицательный индекс” в квадратных скобках на практике становится доступом к свойству объекта по имени
"-1", то есть это не элемент массива и не влияет наlength.
arr.push(x) и arr[arr.length] = x относится к эффекту на содержимое и length, но не к возвращаемому значению: push возвращает новое значение length, а оператор присваивания возвращает присвоенное значение (например, 0).Примеры и проверки
Ниже показаны проверки, которые позволяют увидеть отличия в результате и в length.
Пример 1: сравнение push и arr[arr.length]
const a = [1,2,3,4,5];
const b = [1,2,3,4,5];
const r1 = a.push(0);
const r2 = (b[b.length] = 0);
console.log(a, a.length, r1);
console.log(b, b.length, r2);
Ожидаемая логика:
aиbстанут[1,2,3,4,5,0].a.lengthиb.lengthстанут6.r1будет6, аr2будет0.
Пример 2: почему arr[-1] “не последний элемент”
const arr = [1,2,3,4,5];
arr[-1] = 0;
console.log(arr.length); // 5
console.log(arr[-1]); // 0
console.log(arr[4]); // 5
Объяснение наблюдения: значение хранится в свойстве "-1", а не в “последнем элементе массива”.
Пример 3: безопасный доступ к последнему элементу
const arr = [1,2,3,4,5];
const last = arr[arr.length - 1];
console.log(last); // 5
Кратко: эквивалентное воздействие на массив (добавление 0 в конец и увеличение length) даёт только arr[arr.length] = 0;, тогда как arr[0] = 0; и arr[arr.length - 1] = 0; перезаписывают существующие элементы, а arr[-1] = 0; создаёт обычное свойство "-1", не меняя length.