Avatar ·

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

Всем привет! Я только начал изучать JavaScript и столкнулся с такой проблемой: мне нужно написать функцию, которая принимает какой-то аргумент и выполняет разные действия в зависимости от того, массив это или обычный объект. Но я не могу понять, как правильно это проверить. Пробовал использовать typeof, но он возвращает "object" как для массива, так и для обычного объекта. Например: ```javascript const arr = [1, 2, 3]; const obj = { name: 'John' }; console.log(typeof arr); // "object" console.log(typeof obj); // "object" ``` Я также пробовал проверять через `arr instanceof Array`, но слышал, что этот способ может не работать, если массив был создан в другом окне или фрейме. Ещё видел в интернете совет использовать `arr.constructor === Array`, но тоже не уверен в надёжности. Подскажите, пожалуйста, какой самый правильный и универсальный способ проверить, является ли переменная массивом? Нужно, чтобы метод работал во всех современных браузерах и окружениях (Node.js тоже). Заранее спасибо! <<>>

Лучший способ: статический метод Array.isArray()

Самый надёжный и рекомендуемый способ проверить, является ли объект массивом в JavaScript — использовать статический метод Array.isArray(). Он был добавлен в стандарт ECMAScript 5.1 и поддерживается всеми современными браузерами и средами выполнения, включая Node.js, начиная с версии 0.6.0.

Вот как это работает:

const arr = [1, 2, 3];
const obj = { name: 'John' };
const str = 'hello';
const num = 42;
const func = () => {};

console.log(Array.isArray(arr));   // true
console.log(Array.isArray(obj));   // false
console.log(Array.isArray(str));   // false
console.log(Array.isArray(num));   // false
console.log(Array.isArray(func));  // false

// Даже с массивами из других контекстов (например, iframe) всё работает
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
const iframeArray = iframe.contentWindow.Array;
const arrFromIframe = new iframeArray(1, 2, 3);
console.log(Array.isArray(arrFromIframe)); // true — метод надёжен!

Почему Array.isArray() — лучший выбор?

  • Надёжность: Метод не подвержен проблемам с разными глобальными контекстами (iframe, фреймы, разные окна).
  • Простота: Читаемый и понятный код без лишних конструкций.
  • Производительность: Внутренняя реализация в движках JavaScript оптимизирована и работает быстрее, чем ручные проверки.
  • Безопасность: Не может быть переопределён случайно (в отличие от проверки через instanceof, если прототип был изменён).

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

1. typeof — как вы уже заметили, возвращает "object" как для массивов, так и для объектов, null и даже для некоторых других типов (например, typeof null === "object" — это известная ошибка языка).

2. instanceof Array — работает в большинстве случаев, но ломается, когда массив создан в другом контексте (например, в iframe или при передаче данных между разными окнами браузера). В таких случаях instanceof может вернуть false для настоящего массива.

3. obj.constructor === Array — аналогичная проблема: конструктор может отличаться в разных контекстах. Кроме того, свойство constructor может быть легко переопределено:

const fakeArray = { 0: 'a', 1: 'b', length: 2 };
fakeArray.constructor = Array;
console.log(fakeArray.constructor === Array); // true — хотя это не массив!

Пример использования в реальном коде

function processData(data) {
  if (Array.isArray(data)) {
    console.log('Это массив! Обрабатываем элементы:');
    data.forEach((item, index) => {
      console.log(`Элемент ${index}: ${item}`);
    });
  } else if (typeof data === 'object' && data !== null) {
    console.log('Это объект! Обрабатываем ключи:');
    for (const key in data) {
      if (data.hasOwnProperty(key)) {
        console.log(`${key}: ${data[key]}`);
      }
    }
  } else {
    console.log('Это примитив или null:', data);
  }
}

processData([1, 2, 3]);      // Это массив!
processData({a: 1, b: 2});  // Это объект!
processData('hello');        // Это примитив или null: hello

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

<<>>

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

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

function isArray(value) {
  return Object.prototype.toString.call(value) === '[object Array]';
}

console.log(isArray([1, 2]));           // true
console.log(isArray({}));               // false
console.log(isArray('string'));         // false
console.log(isArray(null));             // false

// Работает даже с массивами из iframe
const iframe = document.createElement('iframe');
document.body.appendChild(iframe);
const arrFromIframe = iframe.contentWindow.Array.of(1, 2);
console.log(isArray(arrFromIframe));    // true

Как это работает?

Встроенный метод Object.prototype.toString возвращает строку вида "[object Тип]" для любого значения. Для массивов это всегда "[object Array]". Этот способ:

  • Не зависит от глобального контекста (работает между iframe и окнами);
  • Не может быть переопределён (если только кто-то не переопределит сам Object.prototype.toString, что крайне маловероятно);
  • Работает во всех браузерах, включая Internet Explorer 6+.

Однако сегодня нет причин использовать этот метод вместо Array.isArray(), если вы не поддерживаете очень старые окружения (например, JavaScriptCore из iOS 4 или старые версии Opera). Array.isArray() короче, понятнее и быстрее в современных движках.

Мой совет: используйте Array.isArray() как основной способ, а Object.prototype.toString — только если вам по какой-то причине нужно написать полифилл для очень старых браузеров.