Ручна зміна length масиву
Властивість length у масиві JavaScript особлива: вона не просто показує довжину, а керує кількістю елементів. Якщо змінити її вручну, це напряму вплине на вміст масиву, тому присвоєння length треба сприймати як операцію зміни даних, а не як запис службового числа.
Теорія
TL;DR
lengthдоступна і для читання, і для запису, і присвоєння змінює сам масив.- Менше значення обрізає масив: елементи з більшими індексами зникають безповоротно.
- Більше значення додає порожні слоти (empty items), а не
undefined. - Порожні слоти пропускаються методами
forEach,map,filter,some,reduce. arr.length = 0очищає масив на місці, не створюючи новий.- Некоректне значення (
-1,1.5,'abc') кидаєRangeError: Invalid array length.
Швидкий приклад
const arr = [1, 2, 3, 4, 5];
arr.length = 3;
console.log(arr); // [1, 2, 3]
arr.length = 5;
console.log(arr); // [1, 2, 3, <2 empty items>]Значення, які «повернулися» після збільшення length, не відновлюються: на їх місці порожні слоти.
Зменшення length
const arr = [1, 2, 3, 4, 5];
arr.length = 3;
console.log(arr); // [1, 2, 3]Якщо зменшити length, усі елементи з більшими індексами видаляються. Це той самий результат, що й arr.splice(3), але швидший і без проміжного масиву. Дані втрачені остаточно: повернути length назад не означає повернути значення.
Збільшення length і порожні слоти
const arr = [1, 2, 3];
arr.length = 6;
console.log(arr); // [1, 2, 3, <3 empty items>]
console.log(arr[4]); // undefinedЯкщо збільшити length, додаються порожні слоти (empty items). Вони не дорівнюють undefined, це порожні комірки, яких ніби «немає», тому, наприклад, forEach() їх пропустить.
Різницю між порожнім слотом і справжнім undefined видно так:
const sparse = [1, 2, 3];
sparse.length = 5;
const dense = [1, 2, 3, undefined, undefined];
console.log(4 in sparse); // false, слота немає
console.log(4 in dense); // true, там лежить undefined
let visited = 0;
sparse.forEach(() => visited++);
console.log(visited); // 3, порожні слоти пропущеноТакий масив називають розрідженим (sparse array). Частина операцій усе ж бачить слоти як undefined: це for...of, Array.from(), spread і join(). Через цю неоднозначність розріджених масивів краще уникати, а для заповнення використовувати Array(6).fill(0).
Очищення масиву через length = 0
const arr = [10, 20, 30];
arr.length = 0;
console.log(arr); // []Це зручний спосіб очистити масив без його перестворення. Важлива відмінність від arr = []: присвоєння length = 0 змінює той самий об'єкт, тому всі інші змінні, що посилаються на цей масив, теж побачать порожній масив. Саме тому цей прийом працює і для const.
const first = [1, 2, 3];
const second = first;
first.length = 0;
console.log(second); // [], те саме посиланняЩо важливо знати
| Дія | Що станеться |
|---|---|
arr.length = менше | Обріже масив, зайві елементи видаляться |
arr.length = більше | Додасть порожні слоти в кінець |
arr.length = 0 | Очистить масив на місці |
Читання arr.length | Показує кількість елементів, на одиницю більшу за максимальний індекс |
arr.length = -1 | Кине RangeError: Invalid array length |
Типові помилки
- Вважати, що збільшення
lengthстворюєundefined. Воно створює порожні слоти, і4 in arrповернеfalse. - Розраховувати, що
forEachабоmapпройдуть по нових комірках. Ці методи пропускають порожні слоти, тому лічильники й підсумки будуть меншими за очікувані. - Намагатися відновити дані, повернувши
length. Після зменшення значення втрачені, зворотне збільшення дає лише порожні слоти. - Плутати
arr.length = 0іarr = []. Перше очищає наявний масив для всіх посилань, друге створює новий масив і залишає старий недоторканим для решти коду. - Присвоювати
lengthнекоректне значення.arr.length = -1абоarr.length = 1.5кидаютьRangeError, а не мовчки округлюють. - Судити про «розмір» об'єкта за
length. У звичайного об'єктаlength, це просто властивість, і зміна її нічого не видаляє.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.