Перевірка значення на масив
Щоб перевірити, що значення є масивом, використовують Array.isArray(value): це сучасний і найнадійніший спосіб, що працює навіть з масивами з інших контекстів виконання. Решта прийомів (instanceof, Object.prototype.toString.call(), typeof) або мають обмеження, або не розрізняють масив і звичайний об'єкт.
Теорія
TL;DR
Array.isArray(value), це рекомендований спосіб, працює скрізь і між контекстами.value instanceof Arrayпрацює, але залежить від контексту: у масиву з iframe іншийArray.prototype.Object.prototype.toString.call(value)повертає"[object Array]", універсально, але громіздко.typeof valueдля масиву завжди дає"object", тому для перевірки не годиться.- Масив, це об'єкт, тому будь-яка перевірка «це об'єкт?» пропустить і
{}, іnull.
Швидкий приклад
const value = [1, 2, 3];
console.log(Array.isArray(value)); // true
console.log(value instanceof Array); // true
console.log(Object.prototype.toString.call(value)); // "[object Array]"
console.log(typeof value); // "object"Три перші перевірки відповідають на питання, четверта, ні.
Array.isArray, сучасний і надійний спосіб
Array.isArray([1, 2, 3]); // true
Array.isArray('text'); // false
Array.isArray({}); // falseЧому саме він:
- Працює в усіх сучасних браузерах і в Node.js.
- Правильно визначає масиви навіть з інших контекстів, наприклад з iframe, з Web Worker або з окремого контексту Node.js.
- Не залежить від прототипу: метод перевіряє внутрішній слот значення, а не ланцюжок
__proto__. - Це рекомендований спосіб перевірки.
instanceof Array, старий, але робочий
[1, 2, 3] instanceof Array; // true
'abc' instanceof Array; // falseПроте є застереження:
- Якщо масив створено в іншому вікні або фреймі, результат може бути хибним, бо кожен контекст має власний конструктор
Arrayі власнийArray.prototype.
// Приклад проблеми:
const foreignArray = new window.frames[0].Array(1, 2, 3);
console.log(foreignArray instanceof Array); // false
console.log(Array.isArray(foreignArray)); // trueЩе одна дрібниця: instanceof можна обдурити через Symbol.hasInstance або підміну прототипу, тоді як Array.isArray() такій підміні не піддається.
Перевірка через Object.prototype.toString.call()
Цей спосіб універсальний для будь-яких типів, тому його часто використовують у бібліотеках.
Object.prototype.toString.call([]); // "[object Array]"
Object.prototype.toString.call({}); // "[object Object]"
Object.prototype.toString.call('hi'); // "[object String]"Він теж не залежить від контексту виконання, але повертає рядок, який треба порівнювати вручну, тому код виходить довшим за Array.isArray().
Чому typeof не підходить
typeof []; // "object"typeof не годиться, тому що масив, це об'єкт, і результат завжди буде "object". Той самий рядок повернуть {}, null, new Date() і new Map(), тож жодної корисної інформації про масив ця перевірка не дає.
Порівняння методів
| Метод | Повертає для масиву | Надійність | Коментар |
|---|---|---|---|
Array.isArray(value) | true | Найвища | Найкращий варіант |
value instanceof Array | true | Середня | Залежить від контексту виконання |
Object.prototype.toString.call(value) | "[object Array]" | Висока | Універсальний, але громіздкий |
typeof value | "object" | Нульова | Не розрізняє масиви та інші об'єкти |
Висновок: завжди використовуйте Array.isArray(value), це найточніший і найкоротший спосіб.
Типові помилки
- Перевіряти масив через
typeof value === 'object'. Умова істинна також для{},null,DateіMap. - Забувати про
null.typeof nullтеж"object", тому будь-яка перевірка «об'єкт» має окремо відсіюватиnull. - Покладатися на
instanceofу коді з iframe, Worker чи кількома контекстами. Там на справжньому масиві ви отримаєтеfalse. - Вважати array-like масивом.
arguments,NodeListі об'єкт із полемlengthне є масивами:Array.isArray()повернеfalse. Щоб отримати справжній масив, використовуйтеArray.from(value)або[...value]. - Перевіряти через
value.constructor === Array. Властивістьconstructorлегко перезаписати, до того ж наnullіundefinedтакий код кине помилку.
Коротка відповідь
Для співбесідиКоротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.