Jak sprawdzić, czy obiekt jest tablicą?


2750

Próbuję napisać funkcję, która akceptuje listę ciągów lub pojedynczy ciąg. Jeśli jest to ciąg, to chcę przekonwertować go na tablicę za pomocą tylko jednego elementu, aby móc go zapętlać bez obawy o błąd.

Jak więc sprawdzić, czy zmienna jest tablicą?


Zaokrągliłem różne rozwiązania poniżej i stworzyłem test jsperf . Wszystkie są szybkie, więc po prostu użyj Array.isArray- jest teraz dobrze obsługiwane i działa w różnych ramkach .


6
Myślałem, że chciałeś „sprawdzić, czy obiekt jest tablicą”, ale chcesz sprawdzić, czy „obiekt jest tablicą ciągów, czy pojedynczym ciągiem”. Nie jesteś pewien, czy to widzisz? Czy to tylko ja? Myślałem o czymś takim … czy ja tutaj czegoś brakuje?
rr1g0

149
TL; DR - arr.constructor === Arrayjest najszybszy.
Neta

3
jsben.ch/#/QgYAV - test porównawczy najpopularniejszych sposobów
EscapeNetscape

39
TL; DR - Tablica. isArray (arr) od ES5; i $. isArray (arr) w jQuery.
Ondra Žižka,

6
Pamiętaj tylko, że jeśli z jakiegoś powodu zastąpisz konstruktora prototypem, arr.constructor === Arraytest zwróci wartość false. Array.isArray(arr)wciąż jednak zwraca prawdę.
ghaschel

Odpowiedzi:


976

W nowoczesnych przeglądarkach możesz to zrobić

Array.isArray(obj)

( Obsługiwane przez Chrome 5, Firefox 4.0, IE 9, Opera 10.5 i Safari 5)

Dla kompatybilności wstecznej możesz dodać następujące elementy

# 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]';
  }
};

Jeśli używasz jQuery, możesz użyć jQuery.isArray(obj)lub $.isArray(obj). Jeśli używasz podkreślenia, możesz użyć_.isArray(obj)

Jeśli nie musisz wykrywać tablic utworzonych w różnych ramkach, możesz także użyć instanceof

obj instanceof Array

9
Oto pełna lista obsługiwanych przeglądarekArray.isArray
lightswitch05,

if (typeof Array.isArray === 'undefined') {można zmienić naif(!Array.isArray) {
iMatoria

Za to, co warto, Object.prototype.string.call(obj)można sfałszować, jeśli obiekt ma Symbol.toStringTagna sobie. To powiedziawszy, nie jestem świadomy żadnego środowiska, które jest statkiem, Symbol.toStringTagale nie Array.isArraywydaje się to bezpieczne.
Benjamin Gruenbaum,

5
Dlaczego instanceof Arrayzawodzi, jeśli tablica pochodzi z innej ramki?
NobleUplift,

16
@NobleUplift: instanceof Arraykończy się niepowodzeniem, jeśli tablica pochodzi z innej ramki, ponieważ każda tablica z tej innej ramki ma inny Arraykonstruktor i prototyp. Ze względów kompatybilności / bezpieczeństwa każda ramka ma swoje własne globalne środowisko, w tym obiekty globalne. ObjectGlobalna z jednej ramki różni się od Objectglobalnej od drugiego. To samo dotyczy Arrayglobaliów. Axel Rauschmayer mówi o tym więcej .
jschoi

1943

Metodą podaną w standardzie ECMAScript w celu znalezienia klasy Object jest użycie toStringmetody z Object.prototype.

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

Możesz też użyć typeofdo sprawdzenia, czy jest to ciąg znaków:

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

Lub jeśli nie martwisz się wydajnością, możesz po prostu zrobić concatnową pustą macierz.

someVar = [].concat( someVar );

Istnieje również konstruktor, do którego możesz bezpośrednio zapytać:

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

Sprawdź na dokładną obróbkę z @TJ Crowder na blogu, jak pisał w swoim komentarzu poniżej.

Sprawdź ten test porównawczy, aby dowiedzieć się, która metoda działa lepiej: http://jsben.ch/#/QgYAV

Z @Bharath przekonwertuj ciąg znaków na tablicę za pomocą Es6 dla zadanego pytania:

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

przypuszczać:

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 Tak, toStringto jeden ze sposobów. Robię trochę podsumowania tutaj: blog.niftysnippets.org/2010/09/say-what.html
TJ Crowder

3
typeof new String('beans') > „obiekt”
Ben

16
Jeśli nie chcesz wpisywać „[Object Array]”, użyj Object.prototype.toString.call (someVar) === Object.prototype.toString.call ([]) lub skorzystaj z funkcji wygody, aby uzyskać typ, jeśli nie nie chcę pisać Object.prototype.toString.call
Pramod

13
Używam waniliowego Array.isArray, który działa w „nowoczesnych przeglądarkach” (tj. IE9 + i wszystkich innych). A do obsługi starej przeglądarki używaj podkładki z MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
David Gilbertson

21
Żyj we współczesnym świecie -Array.isArray(obj)
mcfedr

1274

Najpierw sprawdzę, czy Twoja implementacja obsługuje isArray:

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

Możesz także spróbować użyć instanceofoperatora

v instanceof Array

127
v instanceof Arrayzwróci false, jeśli vzostał utworzony w innej ramce ( vjest instancją thatFrame.contentWindow.Arrayklasy).
pepkin88

47
Aby być konkretnym: Array.isArrayjest zdefiniowany jako część ECMAScript 5 / Javascript 1.8.5.
jevon

8
Naprawdę proste i schludne rozwiązanie, ALE isArray nie jest kompatybilny z niektórymi starszymi przeglądarkami (np. IE7 i IE8). Źródło: kangax.github.io/es5-compat-table/#
Wookie88

2
Co powiesz na: if (Array.isArray) zwraca Array.isArray (v); w przeciwnym razie return v instanceof Array;
lewdev

1
lub po prostu:return (Array.isArray && Array.isArray(v)) || (v instanceof Array);
Stijn de Witt

298

jQuery oferuje również $.isArray()metodę:

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
Tylko uwaga, jQuery używa metody toString wewnętrznie: Źródło GitHub
Jacob Squires

5
@JacobWymaga, że ​​to zależy. Właśnie przetestowałem tutaj, najnowsze jQuery na Chrome - $.isArray === Array.isArraypowraca prawda.
Renan

3
@Renan: To dobra rzecz w używaniu jQuery. Zwykle korzysta z najnowocześniejszej i najlepszej metody, aby to zrobić, i nie musisz wykonywać całej funkcji, aby sprawdzić, czego użyć.
respekt

jQuery używa Array.isArrayza kulisami: github.com/jquery/jquery/blob/master/src/core.js#L211
Sergiu

1
Ale nikt nie będzie używał jQuery TYLKO DLA tej funkcji, prawda? Nie chciałbym po prostu pobierać jquery, ponieważ chcę sprawdzić, czy coś jest tablicą: p
Automagisch

106

Jest to najszybszy spośród wszystkich metod (obsługiwane wszystkie przeglądarki):

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

2
Masz rację, to jest najszybsze według testów, które uwzględniłem w pytaniu.
mpen

5
Czy są jakieś wady korzystania z tej metody? Wydaje się znacznie prostszy i skuteczniejszy niż zaakceptowana, najlepsza odpowiedź.
David Meza

@shinobi - po prostu ciekawy (i często to widziałem) - dlaczego określasz warunek if (obj && Array === obj.constructor)w przeciwieństwie do if (obj && obj.constructor === Array)? Czy to zagubione w tłumaczeniu na angielski, a potem na kodowanie? np. anglojęzyczni zwykle pytają „czy obiekt istnieje i czy jego konstruktor pochodzi z klasy tablicy?”, więc przepływ kodu podczas czytania jest bardziej logiczny. czy jest jakiś techniczny powód?
niezsynchronizowany

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();}
niezsynchronizowany

3
@shinobi wszystko dobrze. przypuszczam, że może to być kac z bezpiecznego nawyku - jeśli przypadkowo użyjesz = zamiast ==, nie skompiluje się, ponieważ nie jest to zmienna, którą można przypisać.
niezsynchronizowany

47

Wyobraź sobie, że masz tę tablicę poniżej :

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

JavaScript (nowe i starsze przeglądarki):

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

lub

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

lub

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

nazwij to tak:

isArray(arr);

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

Array.isArray(arr);

jQuery:

$.isArray(arr);

Kątowy:

angular.isArray(arr);

Podkreślenie i Lodash:

_.isArray(arr);

34

Array.isArray działa szybko, ale nie jest obsługiwany przez wszystkie wersje przeglądarek. Możesz zrobić wyjątek dla innych i zastosować uniwersalną metodę:

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

3
Musisz pobrać .toString()metodę z Object.prototype. Teraz używasz window.toString(), co nie jest takie samo.
system

Masz rację. window.toStringrób to samo co Object.prototype.toStringtylko w Chrome.
CruorVult

isArray wcale nie jest szybki. To najwolniejsza metoda.
jemiloii,

Dlaczego nie dodać go do tablicy zamiast do Utils? (Wiem, że nie chcesz dodatkowych właściwości na nowych obiektach tablicowych, ale myślę, że dzieje się tak tylko wtedy, gdy dodasz isArray do Array.prototype.)
David Winiecki

27

Prosta funkcja, aby to sprawdzić:

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

16
Zmniejszyłbym to do jednej linii return object.constructor === Array- ale czy jesteś pewien, że to zwróci się tylko dla tablic?
mpen

12
Można to zrobić za pomocą wszystkich wyrażeń boolowskich. Doprowadza mnie do szału, kiedy widzę if(x) return true; else return false:-) Nawet jeśli jest to odwrócone, powinieneś zanegować wyrażenie.
mpen

3
Powodem, dla którego funkcja ta nie zwraca wartości true dla getElementsByTagName, jest fakt, że wynikiem tej funkcji jest w rzeczywistości kolekcja HTMLCollection, a nie tablica.
Yuval A.,

6
To kończy się niepowodzeniem, jeśli obiekt jest niezdefiniowany lub ma wartość NULL.
John Henckel,

1
@JohnHenckel Zobacz moją odpowiedź stackoverflow.com/a/29400289/34806 bierze pod uwagę zarówno Twoje obawy, jak i pierwszy komentarz, wszystko w jednym wierszu
Dexygen

17

Jak mówi tutaj MDN :

użyj Array.isArray lub Object.prototype.toString.call, aby odróżnić zwykłe obiekty od tablic

Lubię to:

  • Object.prototype.toString.call(arr) === '[object Array]'lub

  • Array.isArray(arr)


17

Jest tylko jedno rozwiązanie liniowe dla tego pytania

x instanceof Array

gdzie x jest zmienną, zwróci true, jeśli x jest tablicą, a false, jeśli nie jest.


O wiele czystszy i bezpieczny w przyszłości! To lub typeofporównanie.
ChristoKiwi

Czy jest to coś, co cieszy się dużym wsparciem przeglądarki? Lubię to.
Dan Zuzevich

1
Niestety nie jest to przydatne bez try / catch, ponieważ jeśli „x” jest obiektem takim jak {}tablica, to pojawia się błąd składniowy.
abalter

15

Możesz sprawdzić typ swojej zmiennej, czy jest to tablica;

var myArray=[];

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

1
Kilka osób już o tym wspomniało instanceof. Myślę, że to zawodzi w kilku dziwnych scenariuszach.
mpen

15

Zrobiłbym funkcję, aby przetestować typ obiektu, z którym masz do czynienia ...

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

możesz napisać proste zdanie if ...

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

12

Robię to w bardzo prosty sposób. Pracuje dla mnie. Jakieś wady?

Array.prototype.isArray = true;

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

7
oszukany przez{isArray:true}
Bergi,

JSON.parse(someDataFromElsewhere).items.isArraymoże zwrócić wartość true (w zależności od danych) i złamać kod.
Roy Tinker,

12

Oto moja próba ulepszenia tej odpowiedzi, biorąc pod uwagę komentarze:

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

Pozbywa się instrukcji if / else i uwzględnia możliwość, że tablica będzie pusta lub niezdefiniowana


Konstruktor nie jest dostępny w ES5
TechTurtle


11

Zaktualizowałem skrzypce jsperf dwiema alternatywnymi metodami oraz sprawdzaniem błędów.

Okazuje się, że metoda definiowania stałej wartości w prototypach „Object” i „Array” jest szybsza niż jakakolwiek inna metoda. To nieco zaskakujący wynik.

/* 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/>");

Te dwie metody nie działają, jeśli zmienna przyjmuje niezdefiniowaną wartość, ale działają, jeśli masz pewność, że mają wartość. Jeśli chodzi o sprawdzanie pod kątem wydajności, czy wartość jest tablicą czy pojedynczą wartością, druga metoda wygląda jak poprawna metoda szybka. Jest nieco szybszy niż „instanceof” w Chrome, dwa razy szybszy niż druga najlepsza metoda w Internet Explorerze, Operze i Safari (na moim komputerze).


9

Wiem, że ludzie szukają pewnego rodzaju surowego podejścia do javascript. Ale jeśli chcesz mniej myśleć, zajrzyj tutaj: http://underscorejs.org/#isArray

_.isArray(object) 

Zwraca true, jeśli obiekt jest tablicą.

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

7
„O ile nie jest zawarty inny tag dla frameworka / biblioteki, oczekuje się czystej odpowiedzi JavaScript”.
Michał Perłakowski

5

Najlepszym rozwiązaniem, jakie widziałem, jest zamiennik przeglądarki typeof na przeglądarkę. Sprawdź rozwiązanie Angusa Crolla tutaj .

Wersja TL; DR znajduje się poniżej, ale artykuł stanowi świetną dyskusję na ten temat, dlatego powinieneś ją przeczytać, jeśli masz czas.

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

Oto moje leniwe podejście:

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

// ...

var test = [],
    wat = {};

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

Wiem, że świętokradztwo polega na „zepsuciu” prototypu, ale wydaje się, że działa znacznie lepiej niż zalecana toStringmetoda .

Uwaga: pułapką tego podejścia jest to, że nie zadziała ono ponad iframegranicami , ale w moim przypadku użycia nie stanowi to problemu.


nie jest już lepsza pod względem wydajności, przynajmniej na FF30 na Ubuntu 64-bit
test30

2
oszukani przez wat = {array_: true}przedmioty.
Bergi,

@Bergi: Tak, to powinno być oczywiste. Jeśli ustawiasz obj.array_ = true, to tylko oszukujesz siebie .
namuol,

@namuol: Niekoniecznie oszukuję się. Często wystarczającą liczbą obiektów są słowniki. Pomyśl o cacheobiekcie do zapamiętywania wyników wyszukiwania, który wykorzystuje ciągi wyszukiwania jako klucze właściwości. Co jeśli użytkownik szuka array_? Czy z tego powodu Twój obiekt staje się tablicą? To tylko błąd.
Bergi,

@namuol: Podejście to wymagałoby również, aby wszystkie zaangażowane strony (w tym używane biblioteki) mogły zgodzić .array_się na użycie tagów do tablic. Tak naprawdę tak nie jest, .arraymoże to znaczyć cokolwiek. Powinieneś przynajmniej użyć ciągu opisowego i zasygnalizować niestosowność dowolnego użycia, np .__isArray = true. Z.
Bergi,

5

Dobry przykład znajduje się w książce Stoyan Stefanov Patterns JavaScript Patterns, która ma obsługiwać wszystkie możliwe problemy, a także wykorzystywać metodę ECMAScript 5 Array.isArray () .

Oto on:

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

Nawiasem mówiąc, jeśli używasz jQuery, możesz użyć jego metody $ .isArray ()


2
+1: dlaczego nie tylko prosty if(!Array.isArray) {...?
Marco Demaio

5

najłatwiejszy i najszybszy sposób sprawdzenia, czy obiekt jest tablicą, czy nie.

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

lub

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

lub możesz zrobić funkcję narzędzia:

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

stosowanie:

isArray(arr); //return true

5

Poniższe informacje można zastosować, jeśli wiesz, że twój obiekt nie ma metody konkat.

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


To dobra sztuczka, ale można ją pominąć ... ale w większości przypadków powinna ona przynieść rezultat
Alireza,

5

Możesz użyć metody isArray, ale wolałbym to sprawdzić

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


Dlaczego wolisz to?
mpen

@mpen Object.getPrototypeOf(yourvariable)zwraca prototyp obiektu Array. Kod jest najszybszy i bezpieczny, na którym można polegać.
STEEL

1
Łatwo jest udaremnić: pastebin.com/MP8d5bCE Czy masz też testy wydajności, aby potwierdzić swoje „najszybsze” roszczenie?
mpen

4

Jeśli jedynymi dwoma rodzajami wartości, które można przekazać do tej funkcji, jest ciąg znaków lub tablica ciągów znaków, zachowaj prostotę i typeofsprawdź, czy istnieje ciąg znaków:

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

Tak ... to by działało w tym scenariuszu, ale ogólnie nie. Skończyło się na tym, że używałem varargs. :)
mpen

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

W poszukiwaniu najkrótszej wersji oto, co do tej pory mam.

Uwaga: nie ma idealnej funkcji, która zawsze wykryłaby wszystkie możliwe kombinacje. Lepiej poznać wszystkie umiejętności i ograniczenia swoich narzędzi, niż oczekiwać magicznego narzędzia.


1
moje niewielkie pochodzenie, A.map !== undefinedale tak, to może być śliska droga w świecie małpich patcherów;)
dmi3y

FYI: To nie działa w iFrames ( 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

Prosta funkcja do testowania, czy wartością wejściową jest tablica, jest następująca:

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

Działa to w różnych przeglądarkach i starszych przeglądarkach. Jest to pobierane z postu na blogu TJ Crowders


4

Możesz spróbować:

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

Ta funkcja zamieni prawie wszystko w tablicę:

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]"
}

Korzysta z niektórych nowszych funkcji przeglądarki, więc może być konieczne wypełnienie go polifillem w celu uzyskania maksymalnego wsparcia.

Przykłady:

> 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' ]

Ciągi znaków NB zostaną przekonwertowane na tablicę z jednym elementem zamiast tablicy znaków. UsuńisString zaznaczenie, jeśli wolisz na odwrót.

Użyłem Array.isArraytutaj, ponieważ jest to najbardziej solidny, a także najprostszy.


4

W twoim przypadku możesz użyć concatmetody Array, która może akceptować pojedyncze obiekty, a także tablicę (a nawet kombinację):

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 wydaje się być jedną z najstarszych metod Array (nawet IE 5.5 dobrze o tym wie).

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.