Як перевірити, чи об’єкт є масивом?


2751

Я намагаюся написати функцію, яка або приймає список рядків, або одну рядок. Якщо це рядок, то я хочу перетворити його в масив лише з одним елементом, так що я можу перетворити цикл на нього, не боячись помилки.

Тож як я можу перевірити, чи є змінною масив?


Я зібрав різні рішення нижче і створив тест jsperf . Всі вони швидкі, тому просто використовуйте Array.isArray- це зараз добре підтримується і працює в межах кадрів .


6
Я думав, ти маєш намір перевірити, чи об'єкт є масивом, але ти хочеш перевірити, чи "об'єкт - це масив рядків або окрема рядок". Не впевнені, чи бачите ви це? Або це тільки я? Я думав про що - то більш , як це ... я один - то тут відсутній?
rr1g0

149
TL; DR - arr.constructor === Arrayнайшвидший.
Нета

3
jsben.ch/#/QgYAV - орієнтир для найпоширеніших способів
EscapeNetscape

39
TL; DR - масив. isArray (arr) з ES5; і $. isArray (arr) у jQuery.
Ondra Žižka

6
Просто майте на увазі, що якщо ви з якихось причин перезаписаєте конструктор через прототип, arr.constructor === Arrayтест поверне помилкове. Array.isArray(arr)все ще повертає правду, хоча.
ghaschel

Відповіді:


976

У сучасних браузерах ви можете це зробити

Array.isArray(obj)

( Підтримується Chrome 5, Firefox 4.0, IE 9, Opera 10.5 та Safari 5)

Для зворотної сумісності можна додати наступне

# 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

9
Ось більш повний список браузерів, які підтримуютьArray.isArray
lightswitch05

if (typeof Array.isArray === 'undefined') {може бути змінено наif(!Array.isArray) {
iMatoria

Те, що це варто, Object.prototype.string.call(obj)можна сфабрикувати, якщо об’єкт Symbol.toStringTagна ньому є. Це сказало, що я не знаю жодного середовища, яке здійснює судно, Symbol.toStringTagале не Array.isArrayтак це здається безпечним.
Бенджамін Груенбаум

5
Чому не instanceof Arrayвдається, якщо масив є з іншого кадру?
NobleUplift

16
@NobleUplift: instanceof Arrayвиходить з ладу, якщо масив є з іншого кадру, оскільки кожен масив із цього іншого кадру має інший Arrayконструктор та прототип. З міркувань сумісності / безпеки кожен кадр має своє глобальне середовище, і це включає глобальні об'єкти. ObjectГлобальний від одного кадру відрізняється від Objectглобальної від іншого. Так само і для Arrayглобальних. Більше про це говорить Аксель Раушмайер .
jschoi

1943

Метод, наведений у стандарті ECMAScript для пошуку класу Object, полягає у використанні toStringметоду з Object.prototype.

if( Object.prototype.toString.call( someVar ) === '[object Array]' ) {
    alert( 'Array!' );
}

Або ви можете використати typeofдля тестування, чи це String:

if( typeof someVar === 'string' ) {
    someVar = [ someVar ];
}

Або якщо вас не турбує продуктивність, ви можете просто зробити concatновий порожній масив.

someVar = [].concat( someVar );

Є також конструктор, до якого можна безпосередньо запитувати:

if (somevar.constructor.name == "Array") {
    // do something
}

Ознайомтеся з ретельним зверненням із блогу @TJ Crowder , як це розміщено у його коментарі нижче.

Ознайомтеся з цим орієнтиром, щоб отримати уявлення про те, який метод працює краще: http://jsben.ch/#/QgYAV

З @Bharath конвертувати рядок у масив, використовуючи Es6 для заданого питання:

const convertStringToArray = (object) => {
   return (typeof object === 'string') ? Array(object) : object 
}

припустимо:

let m = 'bla'
let n = ['bla','Meow']
let y = convertStringToArray(m)
let z = convertStringToArray(n)
console.log('check y: '+JSON.stringify(y)) . // check y: ['bla']
console.log('check y: '+JSON.stringify(z)) . // check y: ['bla','Meow']

65
+1 Так, toStringце один із способів. Я тут трохи розбиваюся
TJ Crowder

3
typeof new String('beans') > 'об’єкт'
Бен

16
Якщо ви не хочете вводити "[об’єкт масиву]", використовуйте Object.prototype.toString.call (someVar) === Object.prototype.toString.call ([]) або зробіть функцію зручності, щоб отримати тип, якщо ви не «т хоче ввести Object.prototype.toString.call
Прамод

13
Я використовую ванільний Array.isArray, який працює у "сучасних браузерах" (тобто IE9 + та всіх інших). А для старої підтримки браузера використовуйте shim від MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Девід Гілбертсон,

21
Живіть у сучасному світі -Array.isArray(obj)
mcfedr

1274

Я спершу перевіряю, чи підтримує ваша реалізація isArray:

if (Array.isArray)
    return Array.isArray(v);

Ви також можете спробувати скористатися instanceofоператором

v instanceof Array

127
v instanceof Arrayповерне помилкову, якщо вона vбула створена в іншому кадрі ( vце екземпляр thatFrame.contentWindow.Arrayкласу).
pepkin88

47
Щоб бути конкретним: Array.isArrayвизначається як частина ECMAScript 5 / Javascript 1.8.5.
jevon

8
Дійсно просте і акуратне рішення, але isArray не сумісний із деякими старими браузерами (наприклад, IE7 та IE8). Джерело: kangax.github.io/es5-compat-table/#
Wookie88

2
Як щодо: якщо (Array.isArray) повернути Array.isArray (v); else return v instanceof Array;
lewdev

1
або просто:return (Array.isArray && Array.isArray(v)) || (v instanceof Array);
Штійн де Вітт

298

jQuery також пропонує $.isArray()метод:

var a = ["A", "AA", "AAA"];

if($.isArray(a)) {
  alert("a is an array!");
} else {
  alert("a is not an array!");
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


27
Лише зауважте, jQuery використовує метод toString внутрішньо: Джерело GitHub
Jacob Squires

5
@JacobSquires це залежить. Я щойно перевірив тут, остання версія jQuery в Chrome - $.isArray === Array.isArrayповертається в істину.
Ренан

3
@Renan: Це хороша річ у використанні jQuery. Зазвичай для цього використовується найсучасніший і найкращий метод, і вам не потрібно робити всю функцію, перевіряючи себе, щоб знати, що використовувати.
трепет

jQuery використовується Array.isArrayза кадром: github.com/jquery/jquery/blob/master/src/core.js#L211
Сергій

1
Але ніхто не збирається використовувати jQuery ПІДКЛЮЧЕНО для цієї функціональності, правда? Я не просто завантажую jquery, тому що хочу перевірити, чи щось є масив: p
Automagisch

106

Це найшвидший з усіх методів (підтримуються всі браузери):

function isArray(obj){
    return !!obj && obj.constructor === Array;
}

2
Ви маєте рацію, це найшвидше згідно тестів, які я включив у запитання.
mpen

5
Чи є якісь недоліки використання цього методу? Це здається набагато простішим та ефективнішим, ніж прийнята, найкраща відповідь.
Девід Меза

@shinobi - просто цікаво (і я це часто бачив) - чому ви формулюєте умову if (obj && Array === obj.constructor)на противагу if (obj && obj.constructor === Array)? Це втрачено в перекладі на англійську мову, а потім на кодову річ? наприклад, мовці англійської мови, як правило, запитують "чи існує об'єкт, чи конструктор походить з класу масиву?", тому потік коду при його читанні є більш логічним. чи є якась технічна причина?
несинхронізований

function object_type(o){var t = typeof(o);return ((t==="object") && (o.constructor===Array)) ? "array" : t;} /*allows you to */ switch(object_type(o)){ case 'array': break; case 'object' : o.dosomething();}
несинхронізований

3
@shinobi все добре. я припускаю, що це може бути похмілля з безпечної звички c - якщо ви випадково використовуєте = замість ==, воно не збирається як його не присвоювана змінна.
несинхронізований

47

Уявіть, що у вас є цей масив нижче :

var arr = [1,2,3,4,5];

Javascript (нові та старіші браузери):

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

або

function isArray(arr) {
  return arr instanceof Array;
}

або

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

тоді назвіть це так:

isArray(arr);

Javascript (IE9 +, Ch5 +, FF4 +, Saf5 +, Opera10.5 +)

Array.isArray(arr);

jQuery:

$.isArray(arr);

Кутовий:

angular.isArray(arr);

Підкреслення та Лодаш:

_.isArray(arr);

34

Array.isArray працює швидко, але підтримується не всіма версіями браузерів. Таким чином, ви можете зробити виняток для інших і використовувати універсальний метод:

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

3
Вам потрібно отримати .toString()метод Object.prototype. Зараз ви використовуєте window.toString(), що не те саме.
система

Ти правий. window.toStringзробіть так само, як і Object.prototype.toStringв Chrome.
CruorVult

isArray зовсім не швидкий. Це найповільніший метод.
jemiloii

Чому б просто не додати його в Array, а не Utils? (Я знаю, що ви не хочете зайвих властивостей для нових об’єктів масиву, але я думаю, що це станеться лише якщо ви додасте isArray до Array.prototype.)
David Winiecki

27

Проста функція, щоб перевірити це:

function isArray(object)
{
    return object.constructor === Array;
}

16
Я б звів це до одного рядка return object.constructor === Array- але ви впевнені, що це поверне справжнє лише для масивів?
12.12

12
Можна зробити це з усіма булевими виразами. Коли я бачу: --) if(x) return true; else return falseНавіть якщо це відкинуто назад, ви повинні заперечувати вираз.
12.12

3
Причина цього не повертає істину для getElementsByTagName, полягає в тому, що результат цієї функції насправді є HTMLCollection, а не масив.
Юваль А.

6
Це погано виходить з ладу, якщо об’єкт не визначений або недійсний.
Джон Генкель

1
@JohnHenckel Дивіться мою відповідь stackoverflow.com/a/29400289/34806 він бере до уваги як ваша турбота, а також самого першого коментаря, все в одному рядку
Dexygen

17

Як говорить MDN тут :

використовувати Array.isArray або Object.prototype.toString.call для диференціації регулярних об'єктів від масивів

Подобається це:

  • Object.prototype.toString.call(arr) === '[object Array]', або

  • Array.isArray(arr)


17

Для цього питання існує лише одне рядкове рішення

x instanceof Array

де x - змінна, вона повернеться true, якщо x - масив, а false - якщо ні.


Набагато чистіший і безпечний у майбутньому! Це чи typeofпорівняння.
ChristoKiwi

Це щось, що отримує хороший обсяг браузера? Мені це подобається.
Дан Зузевич

1
На жаль, це насправді не корисно без спроби / лову, оскільки якщо "x" є таким об'єктом , як {}масив, то ви отримуєте синтаксичну помилку.
abalter

15

Ви можете перевірити тип змінної, чи це масив;

var myArray=[];

if(myArray instanceof Array)
{
....
}

1
Кілька людей вже згадували instanceof.. Я думаю, що це не вдається за кількох дивних сценаріїв.
1313

15

Я би зробив функцію перевірити тип об'єкта, з яким ви маєте справу ...

function whatAmI(me){ return Object.prototype.toString.call(me).split(/\W/)[2]; }

// tests
console.log(
  whatAmI(["aiming","@"]),
  whatAmI({living:4,breathing:4}),
  whatAmI(function(ing){ return ing+" to the global window" }),
  whatAmI("going to do with you?")
);

// output: Array Object Function String

тоді ви можете написати простий, якщо заява ...

if(whatAmI(myVar) === "Array"){
    // do array stuff
} else { // could also check `if(whatAmI(myVar) === "String")` here to be sure
    // do string stuff
}

12

Я роблю це дуже просто. Працює для мене. Якісь недоліки?

Array.prototype.isArray = true;

a=[]; b={};
a.isArray  // true
b.isArray  // (undefined -> false)

7
обдурив{isArray:true}
Бергі

JSON.parse(someDataFromElsewhere).items.isArrayможе повернути true (залежно від даних) і порушити ваш код.
Рой Тінкер

12

Це моя спроба покращити цю відповідь, беручи до уваги коментарі:

var isArray = myArray && myArray.constructor === Array;

Він позбавляється від if / else і враховує можливість масиву бути недійсним або невизначеним


конструктор недоступний у ES5
TechTurtle


11

Я оновив загадку jsperf двома альтернативними методами, а також перевірку помилок.

Виявляється, метод, що визначає постійне значення в прототипах «Об’єкт» та «Масив», швидший, ніж будь-який з інших методів. Це дещо дивний результат.

/* Initialisation */
Object.prototype.isArray = function() {
  return false;
};
Array.prototype.isArray = function() {
  return true;
};
Object.prototype._isArray = false;
Array.prototype._isArray = true;

var arr = ["1", "2"];
var noarr = "1";

/* Method 1 (function) */
if (arr.isArray()) document.write("arr is an array according to function<br/>");
if (!noarr.isArray()) document.write("noarr is not an array according to function<br/>");
/* Method 2 (value) - **** FASTEST ***** */
if (arr._isArray) document.write("arr is an array according to member value<br/>");
if (!noarr._isArray) document.write("noarr is not an array according to member value<br/>");

Ці два методи не працюють, якщо змінна приймає невизначене значення, але вони працюють, якщо ви впевнені, що вони мають значення. Що стосується перевірки з врахуванням продуктивності, чи є значення масивом або єдиним значенням, другий метод виглядає як дійсний швидкий метод. Це трохи швидше, ніж "instanceof" у Chrome, вдвічі швидше, ніж другий найкращий метод в Internet Explorer, Opera та Safari (на моїй машині).


9

Я знаю, що люди шукають певного підходу до JavaScript. Але якщо ви хочете менше думати, подивіться тут: http://underscorejs.org/#isArray

_.isArray(object) 

Повертає true, якщо об'єктом є масив.

(function(){ return _.isArray(arguments); })();
=> false
_.isArray([1,2,3]);
=> true

7
"Якщо не включений ще один тег для рамки / бібліотеки, очікується чистий відповідь JavaScript."
Michał Perłakowski

5

Найкраще рішення, яке я бачив - це заміна крос-браузера на typeof. Перевірте рішення Angus Croll тут .

Версія TL; DR наведена нижче, але стаття - це чудове обговорення проблеми, тому вам слід прочитати її, якщо у вас є час.

Object.toType = function(obj) {
    return ({}).toString.call(obj).match(/\s([a-z|A-Z]+)/)[1].toLowerCase();
}
// ... and usage:
Object.toType([1,2,3]); //"array" (all browsers)

// or to test...
var shouldBeAnArray = [1,2,3];
if(Object.toType(shouldBeAnArray) === 'array'){/* do stuff */};

5

Ось мій ледачий підхід:

if (Array.prototype.array_ === undefined) {
  Array.prototype.array_ = true;
}

// ...

var test = [],
    wat = {};

console.log(test.array_ === true); // true
console.log(wat.array_ === true);  // false

Я знаю, що це святотатство "возитися" з прототипом, але, здається, воно працює значно краще, ніж рекомендований toStringметод .

Примітка . Проблема такого підходу полягає в тому, що він не буде працювати через iframeмежі , але для мого використання це не проблема.


це вже не краще з точки зору продуктивності, принаймні, на FF30 на 64-розрядному Ubuntu
test30

2
обдурили wat = {array_: true}об’єкти.
Бергі

@Bergi: Так, це має бути очевидним. Якщо ти встановлюєш obj.array_ = true, то ти лише обманюєш себе .
namuol

@namuol: Я не обов'язково обманюю себе. Досить часто об’єкти використовуються як словники. Придумайте cacheоб’єкт, щоб запам'ятати результати пошуку, який використовує рядки пошуку як ключові властивості. Що робити, якщо користувач шукає array_? Чи стає ваш об’єкт масивом через це? Це просто помилка.
Бергі

@namuol: Також цей підхід вимагає, щоб усі залучені сторони (включаючи використовувані бібліотеки) могли погодитися з тим, що .array_використовується для тегування масивів. Це справді не так, .arrayможе означати що завгодно. Ви повинні принаймні використовувати описовий рядок і сигналізувати про невідповідність довільного використання, наприклад, з .__isArray = true.
Бергі

5

У книзі Стояни Стефанова книга « Шаблони JavaScript» є приємним прикладом, який передбачає, що можна вирішити всі можливі проблеми, а також використовувати метод Array.isArray () ECMAScript 5 .

Отже ось це:

if (typeof Array.isArray === "undefined") {
    Array.isArray = function (arg) {
        return Object.prototype.toString.call(arg) === "[object Array]";
    };
}

До речі, якщо ви використовуєте jQuery, ви можете використовувати його метод $ .isArray ()


2
+1: чому не просто просте if(!Array.isArray) {...?
Марко Демайо

5

найпростіший і найшвидший спосіб перевірити, чи об’єкт є масив чи ні.

 var arr = [];
  arr.constructor.name ==='Array'  //return true;

або

arr.constructor ===Array //return true;

або ви можете зробити функцію утиліти:

function isArray(obj){ return obj && obj.constructor ===Array}

використання:

isArray(arr); //return true

5

Наступне може бути використане, якщо ви знаєте, що ваш об'єкт не має методу concat.

var arr = [];
if (typeof arr.concat === 'function') {
    console.log("It's an array");
}


Це хороший трюк, але його можна буде відмінити ... але більшість випадків має отримати результат
Аліреза

5

Можливо, це метод isArray, але я вважаю за краще проконсультуватися

Object.getPrototypeOf(yourvariable) === Array.prototype


Чому ви віддаєте перевагу цьому?
квітня

@mpen Object.getPrototypeOf(yourvariable)повертає прототип об'єкта Array. І на Код можна покластися найшвидше і безпечно.
СТАЛЬ

1
Зробити це легко: pastebin.com/MP8d5bCE Також у вас є тести на ефективність, щоб створити резервну копію вашої "найшвидшої" заявки?
mpen

4

Якщо єдиними двома видами значень, які можуть бути передані цій функції, є рядок або масив рядків, будьте прості та використовуйте typeofперевірку на можливість рядка:

function someFunc(arg) {
    var arr = (typeof arg == "string") ? [arg] : arg;
}

Так ... це працювало б за цим сценарієм, але не в цілому. У будь-якому разі закінчується використанням varargs. :)
mpen

4
A = [1,2,3]
console.log(A.map==[].map)

У пошуках найкоротшої версії ось що я отримав до цих пір.

Зауважте, немає ідеальної функції, яка завжди виявить усі можливі комбінації. Краще знати всі здібності та обмеження своїх інструментів, ніж сподіватися на чарівний інструмент.


1
незначне виведення моїх, A.map !== undefinedале так, це могла бути слизька дорога у світі мавпових патчів;)
dmi3y

FYI: Це не працює через плаваючі фрейми ( stackoverflow.com/questions/460256 / ... )
WiredPrairie

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

var ar = ["ff","tt"]
alert(isArray(ar))


4

Ви можете спробувати це:

var arr = []; (or) arr = new Array();
var obj = {}; (or) arr = new Object();

arr.constructor.prototype.hasOwnProperty('push') //true

obj.constructor.prototype.hasOwnProperty('push') // false

4

Ця функція перетворить майже все на масив:

function arr(x) {
    if(x === null || x === undefined) {
        return [];
    }
    if(Array.isArray(x)) {
        return x;
    }
    if(isString(x) || isNumber(x)) {
        return [x];
    }
    if(x[Symbol.iterator] !== undefined || x.length !== undefined) {
        return Array.from(x);
    }
    return [x];
}

function isString(x) {
    return Object.prototype.toString.call(x) === "[object String]"
}

function isNumber(x) {
    return Object.prototype.toString.call(x) === "[object Number]"
}

Він використовує деякі новіші функції веб-переглядача, тому, можливо, ви захочете поліфікувати це для отримання максимальної підтримки.

Приклади:

> arr(null);
[]
> arr(undefined)
[]
> arr(3.14)
[ 3.14 ]
> arr(1/0)
[ Infinity ]
> gen = function*() { yield 1; yield 2; yield 3; }
[Function: gen]
> arr(gen())
[ 1, 2, 3 ]
> arr([4,5,6])
[ 4, 5, 6 ]
> arr("foo")
[ 'foo' ]

NB рядки будуть перетворені в масив з одним елементом замість масиву символів. ВидалітьisString чек, якщо ви хочете, щоб це було навпаки.

Я використовував Array.isArrayтут, тому що це найміцніший, а також найпростіший.


4

У вашому випадку ви можете використовувати concatметод Array, який може приймати як об'єкти, так і масив (і навіть комбінований):

function myFunc(stringOrArray)
{
  var arr = [].concat(stringOrArray);

  console.log(arr);

  arr.forEach(function(item, i)
  {
    console.log(i, "=", item);
  })
}

myFunc("one string");

myFunc(["one string", "second", "third"]);

concat здається, це один із найдавніших методів Array (навіть IE 5.5 це добре знає).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.