Avatar ·

Как правильно проверить, является ли переменная массивом в JavaScript?

Всем привет! Я только начал изучать JavaScript и столкнулся с проблемой. Мне нужно проверить, является ли переменная массивом, но я не уверен, как это сделать правильно. Я знаю, что есть оператор `typeof`, но он не работает для массивов — он возвращает `"object"`. Например: ```javascript const arr = [1, 2, 3]; console.log(typeof arr); // "object" — бесполезно! ``` Я пробовал использовать `instanceof Array`, но мне сказали, что это ненадёжно, особенно если код работает с разными фреймами или окнами (iframes). Ещё я видел, как кто-то проверял через `Array.isArray()`, но не понимаю, чем этот метод лучше. Также меня смущает, что в некоторых старых проектах используют `Object.prototype.toString.call(arr) === '[object Array]'`. Это вообще легаси или современный подход? Подскажите, пожалуйста, какой способ считается правильным в 2024 году? Хочется писать код, который будет работать и в браузере, и в Node.js, и не сломается в будущем. Буду благодарен за примеры с пояснениями. P.S. Если можно, объясните ещё, почему `typeof` не подходит для массивов — это же логично, что массив — это объект, но почему тогда нет отдельного типа? <<>>

Лучший способ: Array.isArray()

Начиная с ECMAScript 5.1 (ES5), в JavaScript есть встроенный метод Array.isArray(), который является единственным правильным и надёжным способом проверки, является ли значение массивом. Он работает во всех современных средах (браузеры, Node.js, Deno) и не имеет проблем с кросс-контекстной передачей данных.

const arr = [1, 2, 3];
const notArr = 'строка';
const obj = {foo: 'bar'};

console.log(Array.isArray(arr));    // true
console.log(Array.isArray(notArr)); // false
console.log(Array.isArray(obj));    // false
console.log(Array.isArray(null));   // false

Почему не подходят другие способы?

  • typeof — не различает массивы и обычные объекты. Массивы наследуются от Object.prototype, поэтому typeof [] возвращает "object". Это особенность языка, заложенная ещё в первой версии JavaScript. Для проверки массивов он бесполезен.
  • instanceof Array — работает только в пределах одного глобального контекста (одного окна/фрейма). Если массив был создан в другом iframe или открытом окне, instanceof вернёт false, так как у каждого окна свой конструктор Array.
  • Array.prototype.isPrototypeOf() — имеет те же проблемы, что и instanceof.

Как работает Array.isArray() под капотом?

Метод использует внутреннюю проверку [[Class]] значения. В современных движках это эквивалентно:

Object.prototype.toString.call(value) === '[object Array]'

Этот приём был популярен до появления Array.isArray() и до сих пор встречается в коде, но его использование не рекомендуется, так как:

  • Он менее читаем;
  • Может быть медленнее (хотя разница незначительна);
  • Не является семантически правильным — вы используете метод объекта для проверки типа.

Полный пример с обработкой разных типов данных

function checkIfArray(value) {
  if (Array.isArray(value)) {
    console.log('Это массив! Длина:', value.length);
    return true;
  } else {
    console.log('Это не массив. Тип:', typeof value);
    return false;
  }
}

// Тесты
checkIfArray([1, 2, 3]);        // true
checkIfArray('hello');          // false
checkIfArray({length: 3});      // false (псевдомассив)
checkIfArray(new Set([1, 2]));  // false
checkIfArray(null);             // false

Важное замечание про псевдомассивы

Array.isArray() возвращает true только для настоящих массивов. Псевдомассивы (например, arguments, NodeList, результат document.querySelectorAll()) не являются массивами, даже если у них есть свойство length и числовые ключи. Для их преобразования в массив используйте Array.from() или spread-оператор.

Вывод

В современном JavaScript (ES5+) всегда используйте Array.isArray(). Это надёжный, быстрый и кросс-контекстно-безопасный метод. Если вы поддерживаете очень старые браузеры (IE8 и ниже), используйте полифилл на основе Object.prototype.toString, но в 2024 году такая необходимость практически отсутствует.

<<>>

Альтернативный подход: проверка через constructor

Некоторые разработчики используют свойство constructor для проверки:

const arr = [1, 2, 3];
console.log(arr.constructor === Array); // true

Этот способ работает в большинстве случаев, но имеет два недостатка:

  • Свойство constructor может быть изменено (например, через Object.setPrototypeOf() или при наследовании);
  • Не работает с массивами из других контекстов (iframes), как и instanceof.

Дополнение: как обрабатывать редкие случаи

Если вы работаете с кодом, который может получать массивы из разных окон (например, в расширениях браузера), Array.isArray() — единственный безопасный вариант. Но если вам нужно проверить, является ли объект итерируемым или похожим на массив, используйте:

function isArrayLike(value) {
  return value != null && typeof value[Symbol.iterator] === 'function';
}

console.log(isArrayLike([1,2]));       // true
console.log(isArrayLike('hello'));     // true (строка итерируема)
console.log(isArrayLike(new Set()));   // true

Помните: "массивоподобный" ≠ "массив". Если вам нужен именно массив — используйте Array.isArray(). Если вам нужно что-то, что можно перебрать в цикле — проверяйте наличие Symbol.iterator или свойство length.