Как проверить, является ли переменная массивом в JavaScript? [Дубликат]

1514

Я хотел бы проверить, является ли переменная либо массивом, либо единственным значением в JavaScript.

Я нашел возможное решение...

if (variable.constructor == Array)...

Это лучший способ сделать это?

  • 3
    Проверка того, что объект является массивом, имеет некоторые определенные предостережения ... Ответ Питера - единственный, который вы должны использовать.
  • 1
    @ Энди Похоже, мой ответ не самый лучший. Может быть, вы должны выбрать другой ответ как принятый?
Показать ещё 6 комментариев
Теги:
arrays
variables

24 ответа

1541
Лучший ответ

Существует несколько способов проверки, является ли переменная массивом или нет. Лучшее решение - это тот, который вы выбрали.

variable.constructor === Array

Это самый быстрый метод в Chrome, и, скорее всего, все остальные браузеры. Все массивы - это объекты, поэтому проверка свойства constructor - быстрый процесс для движков JavaScript.

Если у вас возникли проблемы с выяснением, является ли свойство объектов массивом, вы должны сначала проверить, есть ли там свойство.

variable.prop && variable.prop.constructor === Array

Некоторые другие способы:

variable instanceof Array

Этот метод работает в 1/3 скорости в качестве первого примера. Все еще довольно солидно, выглядит чище, если вы все о хорошем коде и не столько о производительности. Обратите внимание, что проверка чисел не работает, так как variable instanceof Number всегда возвращает false. Обновление: instanceof теперь идет 2/3 скорости!

Array.isArray(variable)

Этот последний, на мой взгляд, самый уродливый, и он один из самых медленных. В качестве первого примера используется скорость около 1/5. Array.prototype, на самом деле является массивом. вы можете прочитать об этом здесь https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray

Итак, еще одно обновление

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

Этот парень самый медленный, пытаясь проверить массив. Тем не менее, это универсальный магазин для любого типа, который вы ищете. Однако, поскольку вы ищете массив, используйте самый быстрый метод выше.

Кроме того, я проверил некоторый тест: http://jsperf.com/instanceof-array-vs-array-isarray/33 Так что имейте немного удовольствия и проверьте его.

Примечание. @EscapeNetscape создал еще один тест, так как jsperf.com не работает. http://jsben.ch/#/QgYAV Я хотел убедиться, что исходная ссылка останется, когда jsperf возвращается в сеть.

  • 3
    Чтобы продлить данный ответ, нужно выполнить еще один тест jsperf, используя тестирование функций (.push && .pop), которое является самым быстрым и поддерживается во всех браузерах (даже старых). Уловка в том, что, возможно, объект имеет свойства «push» и «pop», не будучи массивом. Также обратите внимание, что при тестировании, если массив является массивом с объектом, созданным (или переданным) из другого фрейма, большинство тестов не пройдут (так как массив в данном окне отличается от массива в окне кадра). Также есть ловушка, если массив создается с помощью нового массива или буквально как [..]
  • 0
    Интересно, мне придется сделать еще один тест браузера. Chrome 38 в centos 7 имеет push && pop как на 10% быстрее, чем конструктор, однако, chrome 39 в windows 8 имеет конструктор как самый быстрый без тщательного сравнения, так как конструктор работает на 70% быстрее, чем push && pop. Я просто подожду еще несколько тестов, спасибо!
Показать ещё 17 комментариев
957

Вы также можете использовать:

if (value instanceof Array) {
  alert('value is Array!');
} else {
  alert('Not an array');
}

Мне кажется, это довольно элегантное решение, но для каждого из них.

Изменить:

В ES5 теперь также есть:

Array.isArray(value);

Но это сломается на старых браузерах, если вы не используете полисы (в основном... IE8 или аналогичные).

  • 22
    Я предлагаю, на самом деле настаивать на том, чтобы придерживаться этого оператора "instanceof", если вы не работаете с несколькими кадрами. Это правильный способ проверки типа объекта.
  • 39
    Единственный случай, когда это не получится, - это если вы пытаетесь проверить массив или объект, так как Array instanceof Object == true .
Показать ещё 11 комментариев
76

Я заметил, что кто-то упомянул jQuery, но я не знал, что существует функция isArray(). Оказывается, он был добавлен в версию 1.3.

jQuery реализует его, как предлагает Питер:

isArray: function( obj ) {
    return toString.call(obj) === "[object Array]";
},

Положив много веры в jQuery (особенно их методы совместимости с несколькими браузерами), я либо обновляюсь до версии 1.3, либо воспользуюсь их функцией (при условии, что обновление не вызовет слишком много проблем) или используйте этот предложенный метод непосредственно в мой код.

Большое спасибо за предложения.

  • 0
    Смотрите эту статью для хорошего обсуждения по теме. Вывод заключается в использовании этого решения.
  • 1
    Это дает мне ошибку SCRIPT65535 в IE10.
71

Существует множество решений со всеми их собственными причудами. Эта страница дает хороший обзор. Одно из возможных решений:

function isArray(o) {
  return Object.prototype.toString.call(o) === '[object Array]'; 
}
  • 0
    Если вы внимательно читаете, он говорит, что этот метод необходим при работе с многокадровыми документами, что не рекомендуется. Этот метод может легко внести небольшие изменения в функцию "toString".
  • 4
    Для этого дается ссылка, чтобы Бретт мог проверить их и посмотреть, в каком случае его функция должна работать
Показать ещё 2 комментария
61

В современных браузерах (и некоторых устаревших браузерах) вы можете сделать

Array.isArray(obj)

(Поддерживается Chrome 5, Firefox 4.0, IE 9, Opera 10.5 и Safari 5)

Если вам необходимо поддерживать старые версии IE, вы можете использовать ES5-подкладку к polyfill Array.isArray; или добавьте следующее

# only implement if no native implementation is available
if (typeof Array.isArray === 'undefined') {
  Array.isArray = function(obj) {
    return Object.prototype.toString.call(obj) === '[object Array]';
  }
};

Если вы используете jQuery, вы можете использовать jQuery.isArray(obj) или $.isArray(obj). Если вы используете подчеркивание, вы можете использовать _.isArray(obj)

Если вам не нужно обнаруживать массивы, созданные в разных кадрах, вы также можете просто использовать instanceof

obj instanceof Array

Примечание: ключевое слово arguments которое можно использовать для доступа к аргументу функции, не является массивом, хотя оно (как правило) ведет себя как единое целое:

var func = function() {
  console.log(arguments)        // [1, 2, 3]
  console.log(arguments.length) // 3
  console.log(Array.isArray(arguments)) // false !!!
  console.log(arguments.slice)  // undefined (Array.prototype methods not available)
  console.log([3,4,5].slice)    // function slice() { [native code] } 
}
func(1, 2, 3)
  • 3
    Это, наверное, самый лучший и современный подход. Я видел это вместе с полифиллом в MDN, так что это означает, что Mozilla доверяет ему developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
  • 0
    Вы не пропустили там prototype ? Кажется, это должен быть Object.prototype.toString.call .
55

Это старый вопрос, но с той же проблемой я нашел очень элегантное решение, которое хочу поделиться.

Добавление прототипа в массив делает его очень простым

Array.prototype.isArray = true;

Теперь, если у вас есть объект, который вы хотите протестировать, чтобы проверить, нужен ли ему массив, который вам нужен, чтобы проверить новое свойство

var box = doSomething();

if (box.isArray) {
    // do something
}

isArray доступен только в том случае, если его массив

  • 0
    это звучит так круто для меня! это может быть родным. Кстати, это работает, даже когда массив был создан до прототипирования?
  • 5
    @Vitimtk Прототип действует как запасной вариант для реального объекта, поэтому это должно работать, даже если рассматриваемый массив уже существует. Конечно, он не будет работать до того, как будет обработана исходная строка.
Показать ещё 6 комментариев
45

Через Crockford:

function typeOf(value) {
    var s = typeof value;
    if (s === 'object') {
        if (value) {
            if (value instanceof Array) {
                s = 'array';
            }
        } else {
            s = 'null';
        }
    }
    return s;
}

Основным недостатком упоминаний Крокфорда является невозможность правильно определить массивы, созданные в другом контексте, например, window. Эта страница имеет гораздо более сложную версию, если этого недостаточно.

27

Мне лично нравится предложение Питера: https://stackoverflow.com/questions/767486/how-do-you-check-if-a-variable-is-an-array-in-javascript (для ECMAScript 3. Для ECMAScript 5 используйте Array.isArray())

Комментарии к сообщению указывают, однако, что если toString() вообще изменено, этот способ проверки массива завершится с ошибкой. Если вы действительно хотите быть конкретным и убедитесь, что toString() не был изменен, и нет никаких проблем с атрибутом класса объектов ([object Array] - это атрибут класса для объекта, который является массивом), то я рекомендую сделать что-то например:

//see if toString returns proper class attributes of objects that are arrays
//returns -1 if it fails test
//returns true if it passes test and it an array
//returns false if it passes test and it not an array
function is_array(o)
{
    // make sure an array has a class attribute of [object Array]
    var check_class = Object.prototype.toString.call([]);
    if(check_class === '[object Array]')
    {
        // test passed, now check
        return Object.prototype.toString.call(o) === '[object Array]';
    }
    else
    {
        // may want to change return value to something more desirable
        return -1; 
    }
}

Обратите внимание, что в JavaScript. Окончательное руководство. 6-е издание, 7.10, говорит, что Array.isArray() реализуется с использованием Object.prototype.toString.call() в ECMAScript 5. Также обратите внимание, что если вы собираетесь беспокоиться о смене реализации toString(), вам также следует беспокойство о каждом другом встроенном методе тоже. Зачем использовать push()? Кто-то может это изменить! Такой подход глуп. Вышеупомянутая проверка является предлагаемым решением для тех, кто обеспокоен изменением toString(), но я считаю, что проверка не нужна.

  • 1
    Хороший вызов по стандарту ECMAScript 5. Конечно, вы не можете гарантировать, что браузер его поддерживает, но это должен быть первый способ проверки нового кода.
  • 0
    Начну с того, что это немного над моей головой. Однако будет ли такой тест более надежным ?: return Object.prototype.toString.call(o) === Object.prototype.toString.call([]);
19

Когда я разместил этот вопрос, версия JQuery, которую я использовал, не включала функцию isArray. Если бы у меня было это, я бы, вероятно, просто использовал его, полагая, что реализация будет лучшим браузером, независимым способом выполнения этой конкретной проверки типа.

Так как JQuery теперь предлагает эту функцию, я всегда буду использовать ее...

$.isArray(obj);

(начиная с версии 1.6.2) Он по-прежнему реализуется с использованием сравнений строк в форме

toString.call(obj) === "[object Array]"
16

Если вы имеете дело только с EcmaScript 5 и выше, тогда вы можете использовать встроенную функцию Array.isArray

например,

Array.isArray([])    // true
Array.isArray("foo") // false
Array.isArray({})    // false
16

Думаю, я добавлю еще один вариант для тех, кто уже может использовать библиотеку Underscore.js в своем script. Underscore.js имеет функцию isArray() (см. http://underscorejs.org/#isArray).

_.isArray(object) 

Возвращает true, если объект является массивом.

  • 1
    Реализация Array.isArray подчеркивания использует собственный Array.isArray если он доступен, в противном случае он использует метод toString .
  • 1
    Эта же функция присутствует в Lodash
10

Если вы используете Angular, вы можете использовать функцию angular.isArray()

var myArray = [];
angular.isArray(myArray); // returns true

var myObj = {};
angular.isArray(myObj); //returns false

http://docs.angularjs.org/api/ng/function/angular.isArray

  • 0
    Вы также можете использовать не Angular-специфичные, но только IE9 + и все стандартные браузеры: <pre> <code> Array.isArray (myArray); // возвращает true Array.isArray (myObj); // возвращает ложь </ code> </ pre>
9

В Crockford JavaScript Хорошие части существует функция проверки, является ли данный аргумент массивом:

var is_array = function (value) {
    return value &&
        typeof value === 'object' &&
        typeof value.length === 'number' &&
        typeof value.splice === 'function' &&
        !(value.propertyIsEnumerable('length'));
};

Он объясняет:

Сначала мы спрашиваем, правно ли это значение. Мы делаем это, чтобы отклонить нулевые и другие значения фальши. Во-вторых, мы спрашиваем, является ли typeof значением "object". Это будет верно для объектов, массивов и (странно) null. В-третьих, мы спрашиваем, имеет ли значение свойство length, которое является числом. Это всегда будет верно для массивов, но обычно это не для объектов. В-четвертых, мы спрашиваем, содержит ли значение метод сращивания. Это снова будет верно для всех массивов. Наконец, мы спрашиваем, является ли свойство length перечислимым (длина будет создаваться с помощью цикла for for?). Это будет ложно для всех массивов. Это самый надежный тест на массивность, который я нашел. К сожалению, это так сложно.

  • 5
    И это были только хорошие части. Представьте себе, когда выходит «JavaScript The Bad Parts» ...
5

Универсальное решение ниже:

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

Начиная с ECMAScript 5, формальное решение:

Array.isArray(arr)

Кроме того, для старых библиотек JavaScript вы можете найти решение ниже, хотя оно недостаточно точное:

var is_array = function (value) {
    return value &&
    typeof value === 'object' &&
    typeof value.length === 'number' &&
    typeof value.splice === 'function' &&
    !(value.propertyIsEnumerable('length'));
};

Решения от http://www.pixelstech.net/topic/85-How-to-check-whether-an-object-is-an-array-or-not-in-JavaScript

4

Я использовал эту строку кода:

if (variable.push) {
   // variable is array, since AMAIK only arrays have push() method.
}
  • 6
    Это не очень хорошее решение. При таком «решении» любой объект с правдоподобным push свойства будет считаться массивом.
3

упомянутый https://github.com/miksago/Evan.js/blob/master/src/evan.js

  var isArray = Array.isArray || function(obj) {
    return !!(obj && obj.concat && obj.unshift && !obj.callee);};
  • 0
    Почему вы проверяете как concat и unshift , не хватило бы , чтобы проверить на unshift ?
  • 0
    Чем больше методов мы проверяем, что Array имеет перемещение, тем больше он действительно является массивом. Другие объекты могут иметь concat или unshift , но менее вероятно , чтобы иметь и другие.
2

Из w3schools:

function isArray(myArray) {
    return myArray.constructor.toString().indexOf("Array") > -1;
}
2

Для тех, кто кодирует гольф, ненадежный тест с наименьшим количеством символов:

function isArray(a) {
  return a.map;
}

Это обычно используется при перемещении/выравнивании иерархии:

function golf(a) {
  return a.map?[].concat.apply([],a.map(golf)):a;
}

input: [1,2,[3,4,[5],6],[7,[8,[9]]]]
output: [1, 2, 3, 4, 5, 6, 7, 8, 9]
1

Я думаю, используя myObj.constructor == Object и myArray.constructor == Массив - лучший способ. Его почти в 20 раз быстрее, чем использование toString(). Если вы расширяете объекты своими собственными конструкторами и хотите, чтобы эти творения считались "объектами", а это не работает, но в противном случае его путь быстрее. typeof так же быстро, как и метод конструктора, но typeof [] == 'object' возвращает true, что часто будет нежелательным. http://jsperf.com/constructor-vs-tostring

Следует отметить, что null.constructor выдает ошибку, поэтому, если вы можете проверить нулевые значения, вам нужно будет сначала сделать, если (testThing! == null) {}

1

Я создал этот немного кода, который может возвращать истинные типы.

Я пока не уверен в производительности, но это попытка правильно идентифицировать typeof.

https://github.com/valtido/better-typeOf также немного побеседовал об этом здесь http://www.jqui.net/jquery/better-typeof-than-the-javascript-native-typeof/

он работает, подобно текущему типу.

var user = [1,2,3]
typeOf(user); //[object Array]

Он думает, что может потребоваться немного тонкой настройки, и принять во внимание вещи, я не сталкивался или не тестировал их должным образом. поэтому приветствуются дальнейшие улучшения, независимо от того, насколько они эффективны по производительности или неправильно переупорядочивают typeOf.

1

Мне понравился ответ Брайана:

function is_array(o){
    // make sure an array has a class attribute of [object Array]
    var check_class = Object.prototype.toString.call([]);
    if(check_class === '[object Array]')    {
        // test passed, now check
        return Object.prototype.toString.call(o) === '[object Array]';
    } else{
        // may want to change return value to something more desirable
        return -1; 
    }
}

но вы можете просто сделать следующее:

return Object.prototype.toString.call(o) === Object.prototype.toString.call([]);
-3
function isArray(x){
    return ((x != null) && (typeof x.push != "undefined"));
}
-4

Так как свойство .length является специальным для массивов в javascript, вы можете просто сказать

obj.length === +obj.length // true if obj is an array

Underscorejs и несколько других библиотек используют этот короткий и простой трюк.

  • 1
    Не могли бы вы объяснить, как это работает? В основном, что делает «+»?
  • 1
    Это хорошо, но это также верно, когда объект является функцией или строкой, а также любым другим объектом с длиной свойства типа номер. Зачем? Ну, унарный оператор + на самом деле приводит переменную как число. Поэтому в основном они проверяют, является ли obj.length числом. У [объекта Object] нет длины свойства, оно не определено, поэтому, когда вы приводите значение undefined в качестве числа, оно становится NaN, и вышеупомянутая проверка выдается как ложная. Таким образом, он возвращает true, если длина свойства объекта - это число, которое в случае массивов, строк и функций будет истинным. Подчеркивание должно делать больше, чем просто это.
-15

Что-то, с чем я только что придумал:

if (item.length) //This is an array else //not an array

  • 3
    var item = 'this_is_not_an_array';
  • 2
    Это плохое решение! Строка также имеет длину.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню