Как проверить, является ли объект массивом в JavaScript: полное руководство
Вы когда-нибудь ловили себя на мысли: «Вроде бы передали массив, но код падает с ошибкой»? Знакомая ситуация. В JavaScript массивы — это объекты, и простая проверка typeof здесь не сработает. Сегодня мы разберем три основных способа проверить, является ли объект массивом, и выясним, какой из них стоит использовать в реальных проектах.
Почему typeof не подходит?
Прежде чем нырять в дебри, давайте разберемся, почему новички часто спотыкаются на этом месте. В JavaScript массивы — это частный случай объектов. Поэтому оператор typeof для массива вернет "object", а не "array". Попробуйте сами:
const arr = [1, 2, 3];
console.log(typeof arr); // "object" — бесполезно
Более того, typeof null === "object" — это известный баг языка, который уже не исправят. Так что если вы проверяете данные от пользователя или из API, опираться на typeof нельзя. Нужны более надежные методы.
Метод 1: Array.isArray() — современный стандарт
Начиная с ES5 (2009 год) в JavaScript появился встроенный метод Array.isArray(). Это самый правильный и простой способ проверить, является ли объект массивом.
const arr = [10, 20, 30];
const notArr = { length: 3, 0: 'a', 1: 'b', 2: 'c' };
console.log(Array.isArray(arr)); // true
console.log(Array.isArray(notArr)); // false
console.log(Array.isArray('hello')); // false
console.log(Array.isArray(null)); // false
Почему это лучший выбор? Потому что Array.isArray() работает корректно даже в многогранных сценариях: если массив пришел из другого iframe или фрейма, instanceof может сломаться, а Array.isArray() — нет. Он проверяет внутренний тип [[Class]] объекта, а не цепочку прототипов.
Поддержка браузеров
Метод поддерживается всеми современными браузерами, включая Internet Explorer 9+. Если вам нужно поддерживать совсем старые браузеры (IE 8 и ниже), используйте полифилл или третий метод.
Метод 2: instanceof Array — классика жанра
Оператор instanceof проверяет, присутствует ли прототип Array.prototype в цепочке прототипов объекта. Звучит сложно, но на практике это работает так:
const arr = [1, 2, 3];
console.log(arr instanceof Array); // true
const obj = { a: 1 };
console.log(obj instanceof Array); // false
// А вот тут сюрприз:
const iframeArr = new iframe.contentWindow.Array(1, 2, 3);
console.log(iframeArr instanceof Array); // false! (если массив из другого фрейма)
Вот в чем подвох: если у вас на странице несколько iframe или вы работаете с Web Workers, массивы из разных глобальных контекстов имеют разные прототипы. instanceof этого не учитывает и может выдать false для настоящего массива. Поэтому в современной разработке от instanceof для проверки массивов лучше отказаться.
Метод 3: Object.prototype.toString.call() — универсальный солдат
Этот способ использовали до появления Array.isArray(). Он до сих пор актуален, если вам нужно написать полифилл или работать в среде, где Array.isArray недоступен.
function isArray(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
}
console.log(isArray([1, 2])); // true
console.log(isArray({ a: 1 })); // false
console.log(isArray('string')); // false
console.log(isArray(null)); // false
Как это работает? Метод toString объекта Object.prototype возвращает строку вида [object Type]. Для массивов это всегда [object Array]. Этот способ обходит проблему с iframe, потому что проверяет внутренний слот [[Class]], который не зависит от глобального контекста.
Сравнение всех подходов: что выбрать?
Давайте сведем все в наглядную таблицу (мысленно, но очень полезную):
- Array.isArray() — лучший выбор. Простой, быстрый, надежный. Работает везде, кроме совсем древних IE. Используйте его всегда, когда это возможно.
- instanceof Array — подходит только для простых скриптов без iframe. Не рекомендуется для серьезных проектов.
- Object.prototype.toString.call() — универсальный запасной вариант. Используйте для полифиллов или если нужно поддерживать очень старые браузеры.
Вот пример полифилла для Array.isArray() на случай, если вы застряли в прошлом десятилетии:
if (!Array.isArray) {
Array.isArray = function(arg) {
return Object.prototype.toString.call(arg) === '[object Array]';
};
}
Практические примеры: где это реально нужно
Давайте посмотрим, как проверка на массив применяется в реальном коде. Представьте, что вы пишете функцию, которая принимает либо один элемент, либо массив элементов, и обрабатывает их единообразно:
function processItems(items) {
// Приводим к массиву, если передан один элемент
if (!Array.isArray(items)) {
items = [items];
}
items.forEach(item => {
console.log('Обработка:', item);
});
}
processItems('один элемент'); // Работает
processItems(['a', 'b', 'c']); // Тоже работает
processItems(null); // Упс! Падает с ошибкой
Видите проблему? Если передать null, то Array.isArray(null) вернет false, и мы попытаемся сделать [null], что технически корректно, но может быть не тем, что вы ожидали. Всегда проверяйте краевые случаи:
function safeProcessItems(items) {
if (items === null || items === undefined) {
console.warn('Передан null или undefined');
return;
}
const arr = Array.isArray(items) ? items : [items];
arr.forEach(item => console.log('Безопасная обработка:', item));
}
Типичные ошибки и как их избежать
Вот несколько граблей, на которые наступают даже опытные разработчики:
- Проверка
typeof arr === 'object' && arr.length— не работает, потому что у объекта тоже может быть свойствоlength. Пример:argumentsили псевдомассивы. - Проверка
arr.constructor === Array— может сломаться, если кто-то переопределилconstructorили если объект создан в другом контексте. - Использование
instanceofв браузерных расширениях —