Что выведет консоль в случае присвоения свойства массиву по строковому индексу?
Дан код:
const a = [1, 2, 4];
a["7"] = 3;
console.log(a); // Первый
console.log(a.length); // Второй
console.log(a.map((item) => item)); // Третий
a.forEach((item) => console.log(item)); // Четвёртый
Что выведетcя в console.log-ах? ƒ
Теория по задаче
Основная концепция: массивы как объекты
В JavaScript массивы — это особый тип объектов. Это фундаментальное понимание объясняет все неочевидные моменты в задаче.
typeof []; // "object"
Array.isArray([]); // true
Индексация массивов
Числовые индексы:
const arr = [1, 2, 3];
// Фактически создаётся объект:
// {
// 0: 1,
// 1: 2,
// 2: 3,
// length: 3,
// __proto__: Array.prototype
// }
Строковые ключи:
const arr = [1, 2, 3];
arr["test"] = "значение"; // Строковой ключ
console.log(arr.test); // "значение"
console.log(arr.length); // 3 — не изменилось!
Ключевой момент: Когда строка может быть преобразована в число, она используется как числовой индекс:
arr["2"] = 100; // Эквивалентно arr[2] = 100
arr["07"] = 200; // "07" → строковой ключ, не числовой индекс
Свойство length
Особенности поведения:
- Автоматическое обновление:
const arr = [1, 2, 3];
arr[10] = 99;
console.log(arr.length); // 11
- Двусторонняя связь:
const arr = [1, 2, 3, 4, 5];
arr.length = 2;
console.log(arr); // [1, 2] - элементы удалены!
arr.length = 5;
console.log(arr); // [1, 2, empty × 3] - пустые слоты
- Формула:
length = наибольший_числовой_индекс + 1
const arr = [];
arr[100] = "x";
console.log(arr.length); // 101
Пустые слоты (Holes) vs undefined
Различие:
// 1. Массив с undefined значениями
const arr1 = [undefined, undefined, undefined];
console.log(arr1); // [undefined, undefined, undefined]
console.log(0 in arr1); // true - свойство существует
// 2. Массив с пустыми слотами
const arr2 = [];
arr2.length = 3;
console.log(arr2); // [empty × 3]
console.log(0 in arr2); // false - свойства нет!
Создать пустые слоты можно несколькими способами:
- Увеличение
length - Пропуск индексов при создании
- Удаление элементов с
delete
Поведение методов массивов
Методы, которые ПРОПУСКАЮТ пустые слоты (не вызывают callback для них):
const sparse = [1, , 3, , 5]; // Индексы 0, 2, 4 существуют
// forEach() - пропускает пустые слоты
let count = 0;
sparse.forEach((v, i) => {
console.log(`Индекс ${i}: ${v}`);
count++;
});
// Вывод: Индекс 0: 1, Индекс 2: 3, Индекс 4: 5
// count = 3 (а не 5!)
// map() - тоже пропускает пустые слоты!
const mapped = sparse.map((v, i) => {
console.log(`map вызван для индекса ${i}`);
return v * 2;
});
// Вывод: map вызван для индекса 0, map вызван для индекса 2, map вызван для индекса 4
console.log(mapped); // [2, empty, 6, empty, 10]
// filter() - тоже пропускает
const filtered = sparse.filter(v => v > 2);
console.log(filtered); // [3, 5] - без пустых слотов!
// reduce() - начинается с первого существующего элемента
const sum = sparse.reduce((acc, v) => acc + v, 0);
console.log(sum); // 9 (1 + 3 + 5), а не NaN или ошибка
Методы, которые НЕ ПРОПУСКАЮТ пустые слоты (обрабатывают их как undefined):
const sparse = [1, , 3];
// Array.from() БЕЗ функции-маппера преобразует empty в undefined
const fromSparse = Array.from(sparse);
console.log(fromSparse); // [1, undefined, 3]
console.log(1 in fromSparse); // true - теперь свойство существует!
// Array.from() С функцией-маппером сначала преобразует, потом применяет
const mappedFrom = Array.from(sparse, x => (x || 0) * 2);
console.log(mappedFrom); // [2, 0, 6] - empty стал 0 после преобразования
// Spread оператор тоже преобразует
const spread = [...sparse];
console.log(spread); // [1, undefined, 3]
Особые случаи:
const sparse = [1, , 3];
// join() - преобразует пустые слоты в пустые строки
console.log(sparse.join('-')); // "1--3"
// Object.keys/values/entries() - видят только существующие свойства
console.log(Object.keys(sparse)); // ["0", "2"]
console.log(Object.values(sparse)); // [1, 3]
// for...in - аналогично Object.keys()
for (let key in sparse) {
console.log(key); // "0", "2"
}
// for...of - ведёт себя как values() для массива
for (let value of sparse) {
console.log(value); // 1, 3 (пустой слот пропущен!)
}
Итого
- Массивы — это объекты: можно использовать строковые ключи
lengthавтоматический: зависит от максимального числового индекса- Пустые ≠
undefined:empty-слоты пропускаются методами массивов - Приведение типов:
a["7"]→a[7]