Skip to main content

typeof для масиву

typeof [] повертає "object", тому що масив у JavaScript, це не окремий тип даних, а спеціалізований об'єкт. Оператор typeof повертає назву типу у вигляді рядка, і серед його можливих відповідей просто немає значення "array".

Теорія

TL;DR

  • typeof [] дорівнює "object", а не "array".
  • Масив, це об'єкт, ключами якого є числові індекси у вигляді рядків, а length зберігає кількість елементів.
  • Список відповідей typeof фіксований: "undefined", "boolean", "number", "bigint", "string", "symbol", "function", "object".
  • Правильна перевірка на масив, це Array.isArray(value).
  • value instanceof Array теж працює, але ламається, коли масив прийшов з іншого realm (iframe, worker, окремий контекст).
  • Object.prototype.toString.call([]) повертає "[object Array]", це старий, але досі робочий прийом.

Швидкий приклад

javascript
console.log(typeof []); // "object" console.log(typeof {}); // "object" console.log(typeof null); // "object" console.log(Array.isArray([])); // true console.log([] instanceof Array); // true

Три різні за змістом значення дають однакову відповідь "object", тому сам по собі typeof не розрізняє масив, звичайний об'єкт і null.

Чому масив, це об'єкт

У специфікації мови масив, це екзотичний об'єкт (exotic object) з особливою поведінкою властивості length. Усередині він влаштований так:

  • ключі, це числові індекси у вигляді рядків ("0", "1", "2");
  • length автоматично оновлюється і завжди на одиницю більший за найбільший індекс;
  • прототипом є Array.prototype, звідки беруться map, filter, push та інші методи.
javascript
const arr = ['a', 'b']; console.log(Object.keys(arr)); // ["0", "1"] console.log(arr.length); // 2 console.log(Object.getPrototypeOf(arr) === Array.prototype); // true

Це видно і з протилежного боку: звичайному об'єкту можна вручну дати індекси й length, і він стане схожим на масив, але справжнім масивом не буде.

javascript
const arrayLike = { 0: 'a', 1: 'b', length: 2 }; console.log(Array.isArray(arrayLike)); // false console.log(Array.from(arrayLike)); // ["a", "b"]

Як коректно перевірити масив

Основний спосіб, це Array.isArray(). Він перевіряє внутрішній слот об'єкта, а не прототип, тому не залежить від контексту виконання.

javascript
Array.isArray([]); // true Array.isArray([1, 2, 3]); // true Array.isArray('abc'); // false Array.isArray({ length: 0 }); // false

Альтернатива, це instanceof, який перевіряє ланцюжок прототипів:

javascript
[] instanceof Array; // true

Він дає правильну відповідь у межах одного вікна, але масив, створений в iframe або в іншому контексті, має власний Array.prototype, і перевірка провалюється:

javascript
const frame = document.createElement('iframe'); document.body.appendChild(frame); const foreignArray = new frame.contentWindow.Array(1, 2, 3); console.log(foreignArray instanceof Array); // false console.log(Array.isArray(foreignArray)); // true

Третій варіант, це виклик стандартного toString, який повертає внутрішній тег об'єкта:

javascript
Object.prototype.toString.call([]); // "[object Array]" Object.prototype.toString.call({}); // "[object Object]" Object.prototype.toString.call(null); // "[object Null]"

Порівняння способів перевірки

ПеревіркаПовертаєКоментар
typeof []"object"Масив, це об'єкт, окремої назви типу немає
Array.isArray([])trueПравильний спосіб, працює між realm
[] instanceof ArraytrueТеж вірно, але залежить від контексту виконання
Object.prototype.toString.call([])"[object Array]"Працює скрізь, але багатослівно
[].constructor === ArraytrueЛегко зламати, перезаписавши constructor

Типові помилки

  • Очікувати від typeof значення "array". Такого результату не існує: набір відповідей оператора фіксований специфікацією, і масив потрапляє в "object".
  • Перевіряти масив через typeof value === 'object'. Під цю умову підпадають також null, {}, Date, Map і будь-який інший об'єкт.
  • Забувати про null. typeof null теж дорівнює "object", це давня помилка мови, яку залишили заради сумісності. Перед зверненням до властивостей перевіряйте значення окремо.
  • Покладатися на instanceof у коді, що працює з iframe, worker або серверним контекстом. Там значення приходить з іншого realm, і instanceof дасть false на справжньому масиві.
  • Плутати масив і array-like. arguments, NodeList і об'єкт з полем length поводяться схоже, але Array.isArray() для них поверне false. Щоб отримати справжній масив, використовуйте Array.from(value) або [...value].

Коротка відповідь

Для співбесіди
Premium

Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.