Comment vérifier si un objet est un tableau?

2754

J'essaie d'écrire une fonction qui accepte soit une liste de chaînes, soit une seule chaîne. Si c'est une chaîne, je veux la convertir en un tableau avec un seul élément, donc je peux la parcourir sans craindre une erreur.

Alors, comment puis-je vérifier si la variable est un tableau?


J'ai rassemblé les différentes solutions ci-dessous et créé un test jsperf . Ils sont tous rapides, il suffit donc de les utiliser Array.isArray- ils sont désormais bien pris en charge et fonctionnent sur tous les cadres .

mpen
la source
6
Je pensais que vous vouliez «vérifier si l'objet est un tableau», mais vous voulez vérifier si «l'objet est un tableau de chaînes ou une seule chaîne» en particulier. Vous ne savez pas si vous le voyez? Ou est-ce juste moi? Je pensais à quelque chose de plus comme ça ... suis-je celui qui manque quelque chose ici?
rr1g0
149
TL; DR - arr.constructor === Arrayest le plus rapide.
Neta
3
jsben.ch/#/QgYAV - une référence pour les moyens les plus courants
EscapeNetscape
39
TL; DR - Tableau. isArray (arr) depuis ES5; et $. isArray (arr) dans jQuery.
Ondra Žižka
6
Gardez à l'esprit que si vous écrasez votre constructeur via un prototype, ce arr.constructor === Arraytest retournera faux. Array.isArray(arr)renvoie toujours vrai cependant.
ghaschel

Réponses:

979

Dans les navigateurs modernes, vous pouvez le faire

Array.isArray(obj)

( Pris en charge par Chrome 5, Firefox 4.0, IE 9, Opera 10.5 et Safari 5)

Pour des raisons de compatibilité descendante, vous pouvez ajouter les éléments suivants

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

Si vous utilisez jQuery, vous pouvez utiliser jQuery.isArray(obj)ou $.isArray(obj). Si vous utilisez un trait de soulignement, vous pouvez utiliser_.isArray(obj)

Si vous n'avez pas besoin de détecter les tableaux créés dans différents cadres, vous pouvez également simplement utiliser instanceof

obj instanceof Array
Fela Winkelmolen
la source
9
Voici une liste plus complète des navigateurs qui prennent en chargeArray.isArray
lightswitch05
if (typeof Array.isArray === 'undefined') {pourrait être changé enif(!Array.isArray) {
iMatoria
Pour ce qu'il vaut Object.prototype.string.call(obj)peut être falsifié si l'objet a Symbol.toStringTagdessus. Cela dit, je ne suis au courant d'aucun environnement expédié, Symbol.toStringTagmais cela ne Array.isArraysemble pas sûr.
Benjamin Gruenbaum
5
Pourquoi instanceof Arrayéchoue si le tableau provient d'une trame différente?
NobleUplift
16
@NobleUplift: instanceof Arrayéchoue si le tableau provient d'une trame différente car chaque tableau de cette trame différente a un Arrayconstructeur et un prototype différents. Pour des raisons de compatibilité / sécurité, chaque trame a son propre environnement global, et cela inclut les objets globaux. Le Objectglobal d'une trame est différent du Objectglobal d'un autre. De même pour les Arraymondiaux. Axel Rauschmayer en parle davantage .
jschoi
1943

La méthode donnée dans la norme ECMAScript pour trouver la classe d'Object est d'utiliser la toStringméthode à partir de Object.prototype.

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

Ou vous pouvez utiliser typeofpour tester s'il s'agit d'une chaîne:

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

Ou si vous n'êtes pas préoccupé par les performances, vous pouvez simplement faire un concatà un nouveau tableau vide.

someVar = [].concat( someVar );

Il y a aussi le constructeur que vous pouvez interroger directement:

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

Découvrez un traitement approfondi sur le blog de @TJ Crowder , comme indiqué dans son commentaire ci-dessous.

Consultez cette référence pour avoir une idée de la méthode qui fonctionne le mieux: http://jsben.ch/#/QgYAV

De @Bharath, convertissez la chaîne en tableau en utilisant Es6 pour la question posée:

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

supposer:

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']
user113716
la source
65
+1 Ouaip, toStringest l'une des voies à suivre. Je fais un petit tour d' horizon
TJ Crowder
3
typeof new String('beans') > 'objet'
Ben
16
Si vous ne voulez pas taper "[tableau d'objets]", utilisez Object.prototype.toString.call (someVar) === Object.prototype.toString.call ([]) ou créez une fonction pratique pour obtenir le type si vous ne le faites pas. ne veux pas taper Object.prototype.toString.call
Pramod
13
J'utilise le vanilla Array.isArray qui fonctionne dans les «navigateurs modernes» (c'est-à-dire IE9 + et tout le monde). Et pour l'ancien support du navigateur, utilisez le shim de MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
David Gilbertson
21
Vivez dans le monde moderne -Array.isArray(obj)
mcfedr
1274

Je voudrais d'abord vérifier si votre implémentation prend en charge isArray:

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

Vous pouvez également essayer d'utiliser l' instanceofopérateur

v instanceof Array
ChaosPandion
la source
127
v instanceof Arrayretournera false si a vété créé dans un autre cadre ( vest une instance de thatFrame.contentWindow.Arrayclasse).
pepkin88
47
Pour être précis: Array.isArrayest défini dans le cadre d'ECMAScript 5 / Javascript 1.8.5.
jevon
8
Solution vraiment simple et soignée MAIS isArray n'est pas compatible avec certains navigateurs plus anciens (ex IE7 et IE8). Source: kangax.github.io/es5-compat-table/#
Wookie88
2
Que diriez-vous: si (Array.isArray) retourne Array.isArray (v); else return v instanceof Array;
lewdev
1
ou tout simplement:return (Array.isArray && Array.isArray(v)) || (v instanceof Array);
Stijn de Witt
298

jQuery propose également une $.isArray()méthode:

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>

janr
la source
27
Juste une note, jQuery utilise la méthode toString en interne: GitHub Source
Jacob Squires
5
@JacobSquires cela dépend. Je viens de tester ici, le dernier jQuery sur Chrome - $.isArray === Array.isArrayrevient vrai.
Renan
3
@Renan: C'est la bonne chose à propos de l'utilisation de jQuery. Il utilise généralement la méthode la plus moderne et la meilleure pour le faire, et vous n'avez pas besoin de vérifier toutes les fonctionnalités vous-même pour savoir quoi utiliser.
admiration
jQuery utilise Array.isArrayles coulisses: github.com/jquery/jquery/blob/master/src/core.js#L211
Sergiu
1
Mais personne n'utilisera jQuery JUSTE POUR cette fonctionnalité, non? Je ne téléchargerais pas simplement jquery parce que je veux vérifier si quelque chose est un tableau: p
Automagisch
106

C'est la plus rapide de toutes les méthodes (tous les navigateurs pris en charge):

function isArray(obj){
    return !!obj && obj.constructor === Array;
}
shinobi
la source
2
Vous avez raison, c'est le plus rapide selon les tests que j'ai inclus dans la question.
mpen
5
Y a-t-il des inconvénients à utiliser cette méthode? Cela semble beaucoup plus simple et efficace que la meilleure réponse acceptée.
David Meza
@shinobi - juste curieux (et je l'ai vu souvent) - pourquoi prononcez-vous la condition if (obj && Array === obj.constructor)par opposition à if (obj && obj.constructor === Array)? Est-ce une perte de traduction en anglais, puis de coder? Par exemple, les anglophones ont généralement tendance à demander "l'objet existe-t-il et son constructeur provient-il de la classe array?", donc le flux de code lors de sa lecture est plus logique. ou y a-t-il une raison technique?
non synchronisé
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();}
non synchronisé
3
@shinobi tout va bien. Je suppose que cela pourrait être une gueule de bois d'une habitude sûre - si vous utilisez accidentellement = à la place ==, il ne serait pas compilé car ce n'est pas une variable assignable.
non synchronisé
47

Imaginez que vous avez ce tableau ci - dessous :

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

Javascript (nouveaux navigateurs et anciens):

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

ou

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

ou

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

puis appelez-le comme ceci:

isArray(arr);

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

Array.isArray(arr);

jQuery:

$.isArray(arr);

Angulaire:

angular.isArray(arr);

Souligner et Lodash:

_.isArray(arr);
Alireza
la source
34

Array.isArray fonctionne rapidement, mais il n'est pas pris en charge par toutes les versions de navigateurs. Vous pouvez donc faire une exception pour les autres et utiliser la méthode universelle:

    Utils = {};    
    Utils.isArray = ('isArray' in Array) ? 
        Array.isArray : 
        function (value) {
            return Object.prototype.toString.call(value) === '[object Array]';
        }
CruorVult
la source
3
Vous devez obtenir la .toString()méthode Object.prototype. En ce moment, vous utilisez le window.toString(), qui n'est pas le même.
le système du
Tu as raison. window.toStringfaites la même chose que Object.prototype.toStringdans Chrome.
CruorVult
isArray n'est pas rapide du tout. C'est la méthode la plus lente.
jemiloii
Pourquoi ne pas simplement l'ajouter à Array plutôt qu'à Utils? (Je sais que vous ne voulez pas de propriétés supplémentaires sur les nouveaux objets de tableau, mais je pense que cela ne se produit que si vous ajoutez isArray à Array.prototype.)
David Winiecki
27

Fonction simple pour vérifier cela:

function isArray(object)
{
    return object.constructor === Array;
}
MidnightTortoise
la source
16
Je réduirais cela à une seule ligne return object.constructor === Array- mais êtes-vous sûr que cela ne reviendra que sur les tableaux?
mpen
12
Peut le faire avec toutes les expressions booléennes. Me rend fou quand je vois if(x) return true; else return false:-) Même si c'est à l'envers, vous devez annuler l'expression.
mpen
3
La raison pour laquelle cela ne retourne pas true pour getElementsByTagName, est que le résultat de cette fonction est en fait un HTMLCollection et non un tableau.
Yuval A.
6
Cela échoue mal si l'objet n'est pas défini ou est nul.
John Henckel
1
@JohnHenckel Voir ma réponse stackoverflow.com/a/29400289/34806 elle prend en compte à la fois votre préoccupation ainsi que le tout premier commentaire, le tout sur une seule ligne
Dexygen
17

Comme MDN le dit ici :

utilisez Array.isArray ou Object.prototype.toString.call pour différencier les objets réguliers des tableaux

Comme ça:

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

  • Array.isArray(arr)

ajax333221
la source
17

Il n'y a qu'une solution de ligne pour cette question

x instanceof Array

où x est la variable, il retournera vrai si x est un tableau et faux s'il ne l'est pas.

Vikash Kumar
la source
Beaucoup plus propre et sûr pour l'avenir! Ceci ou une typeofcomparaison.
ChristoKiwi
Est-ce quelque chose qui reçoit une bonne quantité de support du navigateur? Je l'aime.
Dan Zuzevich
1
Malheureusement, cela n'est pas vraiment utile sans try / catch car si "x" est un objet tel qu'un {}tableau, alors vous obtenez une erreur de syntaxe.
abalter
15

Vous pouvez vérifier le type de votre variable s'il s'agit d'un tableau avec;

var myArray=[];

if(myArray instanceof Array)
{
....
}
Ahmet DAL
la source
1
Quelques personnes l'ont déjà mentionné instanceof.. Je pense que cela échoue dans quelques scénarios étranges.
mpen
15

Je ferais une fonction pour tester le type d'objet que vous traitez ...

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

alors vous pouvez écrire une simple instruction if ...

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

Je le fais d'une manière très simple. Travaille pour moi. Des inconvénients?

Array.prototype.isArray = true;

a=[]; b={};
a.isArray  // true
b.isArray  // (undefined -> false)
rsbkk
la source
7
dupé par{isArray:true}
Bergi
JSON.parse(someDataFromElsewhere).items.isArraypourrait retourner vrai (selon les données) et casser votre code.
Roy Tinker
12

C'est ma tentative d'améliorer cette réponse en tenant compte des commentaires:

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

Il supprime le if / else et explique la possibilité que le tableau soit nul ou non défini

Dexygen
la source
constructeur n'est pas disponible dans ES5
TechTurtle
11

J'ai mis à jour le violon jsperf avec deux méthodes alternatives ainsi que la vérification des erreurs.

Il s'avère que la méthode définissant une valeur constante dans les prototypes «Objet» et «Tableau» est plus rapide que toutes les autres méthodes. C'est un résultat quelque peu surprenant.

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

Ces deux méthodes ne fonctionnent pas si la variable prend la valeur non définie, mais elles fonctionnent si vous êtes certain qu'elles ont une valeur. En ce qui concerne la vérification en tenant compte des performances si une valeur est un tableau ou une valeur unique, la deuxième méthode ressemble à une méthode rapide valide. Il est légèrement plus rapide que «instanceof» sur Chrome, deux fois plus rapide que la deuxième meilleure méthode dans Internet Explorer, Opera et Safari (sur ma machine).

le_top
la source
9

Je sais que les gens recherchent une sorte d'approche javascript brute. Mais si vous voulez y penser moins, jetez un œil ici: http://underscorejs.org/#isArray

_.isArray(object) 

Renvoie vrai si l'objet est un tableau.

(function(){ return _.isArray(arguments); })();
=> false
_.isArray([1,2,3]);
=> true
Eugène
la source
7
"À moins qu'une autre balise pour un framework / bibliothèque ne soit également incluse, une réponse JavaScript pure est attendue."
Michał Perłakowski
5

La meilleure solution que j'ai vue est un remplacement multi-navigateur pour typeof. Consultez la solution d'Angus Croll ici .

La version TL; DR est ci-dessous, mais l'article est une excellente discussion sur le problème, vous devriez donc le lire si vous en avez le temps.

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 */};
John Wundes
la source
5

Voici mon approche paresseuse:

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

// ...

var test = [],
    wat = {};

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

Je sais que c'est un sacrilège de "jouer avec" le prototype, mais il semble fonctionner beaucoup mieux que la toStringméthode recommandée .

Remarque: Un écueil de cette approche est qu'elle ne fonctionnera pas au-delà des iframefrontières , mais pour mon cas d'utilisation, ce n'est pas un problème.

namuol
la source
ce n'est plus mieux en termes de performances, du moins sur FF30 sur Ubuntu 64 bits
test30
2
dupé par les wat = {array_: true}objets.
Bergi
@Bergi: Oui, cela devrait être évident. Si vous vous préparez obj.array_ = true, alors vous vous trompez seulement .
namuol
@namuol: Je ne me trompe pas nécessairement. Souvent, suffisamment d'objets sont utilisés comme dictionnaires. Pensez à un cacheobjet pour mémoriser les résultats de la recherche qui utilise les chaînes de recherche comme clés de propriété. Et si un utilisateur recherche array_? Votre objet devient-il un tableau à cause de cela? C'est juste un bug.
Bergi
@namuol: En outre, cette approche nécessiterait que toutes les parties impliquées (y compris les bibliothèques utilisées) puissent convenir de ce qui .array_est utilisé pour le balisage des tableaux. Ce n'est vraiment pas le cas ici, cela .arraypeut signifier quelque chose. Vous devez au moins utiliser une chaîne descriptive et signaler le caractère inapproprié d'une utilisation arbitraire, par exemple avec .__isArray = true.
Bergi
5

Il y a un bel exemple dans le livre JavaScript Patterns de Stoyan Stefanov qui suppose de gérer tous les problèmes possibles ainsi que d'utiliser la méthode ECMAScript 5 Array.isArray () .

Voici donc:

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

Par ailleurs, si vous utilisez jQuery, vous pouvez utiliser sa méthode $ .isArray ()

Salvador Dali
la source
2
+1: pourquoi pas juste un simple if(!Array.isArray) {...?
Marco Demaio
5

moyen le plus simple et le plus rapide de vérifier si un objet est un tableau ou non.

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

ou

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

ou vous pouvez créer une fonction utilitaire:

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

usage:

isArray(arr); //return true
sheelpriy
la source
5

Ce qui suit peut être utilisé si vous savez que votre objet n'a pas de méthode concat.

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

yesil
la source
C'est une bonne astuce, mais pourrait être annulée ... mais la plupart du temps devrait obtenir le résultat
Alireza
5

Vous pourriez est la méthode isArray mais je préférerais vérifier avec

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

ACIER
la source
Pourquoi préférez-vous cela?
mpen
@mpen Object.getPrototypeOf(yourvariable)retourne le prototype d'un objet Array. Et le code est le plus rapide et le plus sûr.
STEEL
1
C'est facile à déjouer: pastebin.com/MP8d5bCE De plus, avez-vous des tests de performances pour sauvegarder votre réclamation "la plus rapide"?
mpen
4

Si les deux seuls types de valeurs pouvant être passés à cette fonction sont une chaîne ou un tableau de chaînes, restez simple et utilisez une typeofvérification de la possibilité de chaîne:

function someFunc(arg) {
    var arr = (typeof arg == "string") ? [arg] : arg;
}
Tim Down
la source
Ouais ... ça marcherait pour ce scénario, mais pas en général. J'ai fini par utiliser des varargs de toute façon. :)
mpen
4
A = [1,2,3]
console.log(A.map==[].map)

À la recherche de la version la plus courte, voici ce que j'ai obtenu jusqu'à présent.

Notez qu'il n'y a pas de fonction parfaite qui détectera toujours toutes les combinaisons possibles. Il vaut mieux connaître toutes les capacités et les limites de vos outils que d'attendre un outil magique.

exebook
la source
1
légère dérivation de la mienne A.map !== undefinedmais oui, cela pourrait être une route glissante dans le monde des
patcheurs
Pour info: cela ne fonctionne pas sur les 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))
RoboTamer
la source
4

Une fonction simple pour tester si une valeur d'entrée est un tableau est la suivante:

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

Cela fonctionne sur plusieurs navigateurs et avec des navigateurs plus anciens. Ceci est tiré du blog de TJ Crowders

Brad Parks
la source
4

Vous pouvez essayer ceci:

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

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

obj.constructor.prototype.hasOwnProperty('push') // false
VIJAY P
la source
4

Cette fonction transformera presque n'importe quoi en tableau:

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

Il utilise des fonctionnalités de navigateur plus récentes, vous voudrez donc peut-être les remplir pour une prise en charge maximale.

Exemples:

> 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 les chaînes seront converties en un tableau avec un seul élément au lieu d'un tableau de caractères. Supprimez la isStringcoche si vous préférez l'inverse.

Je l'ai utilisé Array.isArrayici parce que c'est le plus robuste et aussi le plus simple.

mpen
la source
4

Dans votre cas, vous pouvez utiliser la concatméthode Array qui peut accepter des objets uniques ainsi que des tableaux (et même combinés):

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 semble être l'une des plus anciennes méthodes d'Array (même IE 5.5 le sait bien).

kolyaseg
la source