Отрицательный индекс в JS-массиве: вывод и length

Дан код:

const b = [1, 2, 4];
b["-7"] = 3;

console.log(b); // Первый
console.log(b.length); // Второй
console.log(b.map((item) => item)); // Третий
b.forEach((item) => console.log(item)); // Четвёртый

Что выведетcя в console.log-ах?

Теория: массивы и свойства

В JavaScript массив является объектом. Это означает, что у массива существуют:

  • Элементы массива по индексам 0, 1, 2, ... (это «индексные» свойства).
  • Обычные свойства объекта с любыми строковыми ключами (например, "foo", "-7" и т.д.).

Запись b["-7"] = 3 добавляет (или изменяет) свойство объекта с именем "-7", а не «элемент массива с индексом -7». Отрицательные «индексы» в JavaScript-массивах не являются индексами массива и не участвуют в механике length.

Ключ свойства при обращении в квадратных скобках фактически является строкой. Поэтому b["2"] и b[2] обращаются к одному и тому же индексному элементу, а b["-7"] — к неиндексному свойству.

Что такое «индекс массива»

У массива есть специальное правило: строковый ключ считается индексом массива только если он выглядит как неотрицательное целое число в канонической форме (например, "0", "1", "2", "10").
Строка "-7" этому условию не соответствует, поэтому:

  • не изменяет length,
  • не участвует в обходах map(), forEach() как элемент массива,
  • не отображается как обычный элемент 0..length-1.

Ниже приведён ориентир по ключам:

Ключ свойстваСчитается индексом массиваВлияет на length
"0", "1", "2"ДаДа (если индекс ≥ текущего length)
"-7"НетНет
"03"Нет (не канонично)Нет
"3.5"НетНет

Разбор кода по шагам

Исходный код:

const b = [1, 2, 4];
b["-7"] = 3;

console.log(b); // Первый
console.log(b.length); // Второй
console.log(b.map((item) => item)); // Третий
console.log(b.forEach((item) => console.log(item))); // Четвёртый

Шаг 1: const b = [1, 2, 4];

  • Создаются элементы: b[0] = 1, b[1] = 2, b[2] = 4.
  • b.length становится 3 (количество позиций до индекса 2 включительно).

Шаг 2: b["-7"] = 3;

  • Создаётся обычное свойство объекта-массива: ключ "-7", значение 3.
  • Элементы b[0], b[1], b[2] не меняются.
  • b.length не меняется, потому что ключ "-7" не индексный.

Состояние можно представить так:

b (Array-объект)
- индексные элементы:
  - "0" -> 1
  - "1" -> 2
  - "2" -> 4
- обычные свойства:
  - "-7" -> 3
- length -> 3

Что выведет каждый console.log

Первый: `console.log(b)`

В консоли будет показан массив с тремя элементами и дополнительным свойством "-7".
Часто это выглядит примерно так: [ 1, 2, 4, '-7': 3 ], но точный формат отображения зависит от среды (браузер, Node.js, настройки DevTools).

Важно, что элементы массива остаются [1, 2, 4], а "-7": 3 — именно свойство, а не «вставка» внутрь списка элементов.

Второй: `console.log(b.length)`

Будет выведено 3.
length связан с индексными ключами (0..length-1) и не увеличивается от присваивания по неиндексному ключу "-7".

Третий: `console.log(b.map((item) => item))`

Будет выведено [1, 2, 4].
map() создаёт новый массив длины b.length и применяет колбэк только к индексным элементам (позициям 0, 1, 2), а свойство "-7" в этот обход не попадает.

Пример того, что делает map() по смыслу:

// Смысловая модель (упрощённо)
const result = [];
for (let i = 0; i < b.length; i++) {
  // берётся именно b[i], а не b["-7"]
  result[i] = b[i];
}
console.log(result);

Четвёртый: `b.forEach((item) => console.log(item))`

Вызов console.log(item) выведет элементы массива по порядку:

1
2
4

Почему варианты-ловушки неверны

  • Варианты с [3, 1, 2, 4] предполагают «вставку в начало» или «сдвиг элементов», но присваивание b["-7"] сдвигов не делает.
  • Варианты с length = 4 предполагают, что добавилось 4-е индексное значение, но ключ "-7" не индексный.
  • Варианты, где map() возвращает ... '-7': 3 ..., неверны, потому что map() обходит индексные позиции 0..length-1, а не произвольные свойства.
  • Вариант «Ошибка TypeError» не подходит, потому что операции корректны: присваивание свойства допустимо, map и forEach существуют у массивов.

Кратко: b["-7"]=3 добавляет неиндексное свойство "-7", поэтому b отображается с этим свойством, length остаётся 3, map() даёт [1,2,4], а forEach() печатает 1 2 4 и возвращает undefined, который выводится внешним console.log.