¿Cómo verificar si un objeto es una matriz?

2754

Estoy tratando de escribir una función que acepte una lista de cadenas o una sola cadena. Si es una cadena, entonces quiero convertirla en una matriz con solo un elemento, para poder recorrerla sin temor a un error.

Entonces, ¿cómo verifico si la variable es una matriz?


He redondeado las diversas soluciones a continuación y he creado una prueba jsperf . Todos son rápidos, así que solo úselos Array.isArray, ahora está bien soportado y funciona en todos los marcos .

mpen
fuente
66
Pensé que querías decir 'verificar si el objeto es una matriz', pero quieres verificar si 'el objeto es una matriz de cadenas o una sola cadena' específicamente. ¿No estás seguro si lo ves? O solo soy yo? Estaba pensando en algo más como esto ... ¿Me estoy perdiendo algo aquí?
rr1g0
149
TL; DR : arr.constructor === Arrayes el más rápido.
Neta
3
jsben.ch/#/QgYAV - un punto de referencia para las formas más comunes
EscapeNetscape
39
TL; DR - Matriz. isArray (arr) desde ES5; y $. isArray (arr) en jQuery.
Ondra Žižka
66
Solo tenga en cuenta que si por alguna razón sobrescribe su constructor a través de un prototipo, esa arr.constructor === Arrayprueba devolverá falso. Array.isArray(arr)todavía devuelve cierto sin embargo.
ghaschel

Respuestas:

979

En los navegadores modernos puedes hacer

Array.isArray(obj)

( Compatible con Chrome 5, Firefox 4.0, IE 9, Opera 10.5 y Safari 5)

Para compatibilidad con versiones anteriores, puede agregar lo siguiente

# 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 usa jQuery puede usar jQuery.isArray(obj)o $.isArray(obj). Si usa guión bajo, puede usar_.isArray(obj)

Si no necesita detectar arreglos creados en diferentes marcos, también puede usar instanceof

obj instanceof Array
Fela Winkelmolen
fuente
99
Aquí hay una lista más completa de navegadores compatiblesArray.isArray
lightswitch05
if (typeof Array.isArray === 'undefined') {podría cambiarse aif(!Array.isArray) {
iMatoria
Por lo que vale Object.prototype.string.call(obj)se puede suplantar si el objeto lo tiene Symbol.toStringTag. Dicho esto, no conozco ningún entorno que se envíe, Symbol.toStringTagpero no Array.isArrayasí, esto parece seguro.
Benjamin Gruenbaum
55
¿Por qué instanceof Arrayfalla si la matriz es de un marco diferente?
NobleUplift
16
@NobleUplift: instanceof Arrayfalla si la matriz es de un marco diferente porque cada matriz de ese marco diferente tiene un Arrayconstructor y un prototipo diferentes . Por razones de compatibilidad / seguridad, cada marco tiene su propio entorno global, y esto incluye objetos globales. Lo Objectglobal de un marco es diferente de lo Objectglobal de otro. Así también para los Arrayglobales. Axel Rauschmayer habla más sobre esto .
jschoi
1943

El método dado en el estándar ECMAScript para encontrar la clase de Objeto es usar el toStringmétodo desde Object.prototype.

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

O podría usar typeofpara probar si es una cadena:

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

O si no está preocupado por el rendimiento, puede simplemente hacer una concata una nueva matriz vacía.

someVar = [].concat( someVar );

También está el constructor que puede consultar directamente:

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

Echa un vistazo a un tratamiento exhaustivo del blog de @TJ Crowder , como se publica en su comentario a continuación.

Consulte este punto de referencia para tener una idea de qué método funciona mejor: http://jsben.ch/#/QgYAV

De @Bharath convierte una cadena a una matriz usando Es6 para la pregunta formulada:

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

suponer:

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']
usuario113716
fuente
65
+1 Sí, toStringes una de las formas de ir. Hago un breve
TJ Crowder
3
typeof new String('beans') > 'objeto'
Ben
16
Si no desea escribir "[matriz de objetos]", use Object.prototype.toString.call (someVar) === Object.prototype.toString.call ([]) o realice una función conveniente para obtener el tipo si no lo hace no quiero escribir Object.prototype.toString.call
Pramod
13
Yo uso el Vanilla Array.isArray que funciona en 'navegadores modernos' (es decir, IE9 + y todos los demás). Y para la compatibilidad con navegadores antiguos, use el shim de MDN developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
David Gilbertson
21
Vive en el mundo moderno -Array.isArray(obj)
mcfedr
1274

Primero verificaría si su implementación admite isArray:

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

También puedes intentar usar el instanceofoperador

v instanceof Array
ChaosPandion
fuente
127
v instanceof Arraydevolverá falso si vse creó en otro marco ( ves una instancia de thatFrame.contentWindow.Arrayclase).
pepkin88
47
Para ser específico: Array.isArrayse define como parte de ECMAScript 5 / Javascript 1.8.5.
jevon
8
Solución realmente simple y ordenada PERO isArray no es compatible con algunos navegadores más antiguos (ex IE7 e IE8). Fuente: kangax.github.io/es5-compat-table/#
Wookie88
2
¿Qué tal si if (Array.isArray) devuelve Array.isArray (v); else return v instanceof Array;
lewdev
1
o simplemente:return (Array.isArray && Array.isArray(v)) || (v instanceof Array);
Stijn de Witt
298

jQuery también ofrece un $.isArray()método:

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
fuente
27
Solo una nota, jQuery utiliza el método toString internamente: Fuente GitHub
Jacob Squires
55
@JacobSquires depende. Acabo de probar aquí, la última jQuery en Chrome, $.isArray === Array.isArrayestá volviendo verdadera.
Renan
3
@ Renan: Esto es lo bueno de usar jQuery. Por lo general, utiliza el método más moderno y mejor para hacerlo, y no tiene que hacer todas las funciones comprobándose usted mismo para saber qué usar.
temor
jQuery está utilizando Array.isArraydetrás de escena: github.com/jquery/jquery/blob/master/src/core.js#L211
Sergiu
1
Pero nadie va a usar jQuery SOLO PARA esta funcionalidad, ¿verdad? No solo descargaría jquery porque quiero verificar si algo es una matriz: p
Automagisch
106

Este es el más rápido entre todos los métodos (todos los navegadores compatibles):

function isArray(obj){
    return !!obj && obj.constructor === Array;
}
shinobi
fuente
2
Tienes razón, eso es lo más rápido según las pruebas que incluí en la pregunta.
mpen
55
¿Hay alguna desventaja al usar este método? Parece mucho más simple y efectivo que la respuesta superior aceptada.
David Meza
@shinobi - solo curiosidad (y he visto esto a menudo) - ¿por qué expresas la condición if (obj && Array === obj.constructor)en lugar de if (obj && obj.constructor === Array)? ¿Se pierde en la traducción al inglés y luego en el código? por ejemplo, los angloparlantes generalmente preguntan "¿existe el objeto, y su constructor proviene de la clase de matriz?", por lo que el flujo de código al leerlo es más lógico. o hay alguna razón técnica?
sincronización
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();}
sincronizar el
3
@shinobi todo bien. supongo que podría ser una resaca de un hábito seguro de c: si accidentalmente usa = en lugar de ==, no se compilaría ya que no es una variable asignable.
sincronización
47

Imagina que tienes esta matriz a continuación :

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

Javascript (navegadores nuevos y antiguos):

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

o

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

o

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

entonces llámalo así:

isArray(arr);

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

Array.isArray(arr);

jQuery:

$.isArray(arr);

Angular:

angular.isArray(arr);

Subrayar y Lodash:

_.isArray(arr);
Alireza
fuente
34

Array.isArray funciona rápido, pero no es compatible con todas las versiones de navegadores. Por lo tanto, puede hacer una excepción para los demás y utilizar el método universal:

    Utils = {};    
    Utils.isArray = ('isArray' in Array) ? 
        Array.isArray : 
        function (value) {
            return Object.prototype.toString.call(value) === '[object Array]';
        }
CruorVult
fuente
3
Necesitas obtener el .toString()método Object.prototype. En este momento estás usando el window.toString(), que no es lo mismo.
el sistema
Tienes razón. window.toStringhaz lo mismo que Object.prototype.toStringsolo en Chrome.
CruorVult
isArray no es rápido en absoluto. Es el método más lento.
jemiloii
¿Por qué no solo agregarlo a Array en lugar de a Utils? (Sé que no desea propiedades adicionales en nuevos objetos de matriz, pero creo que eso solo sucede si agrega isArray a Array.prototype.)
David Winiecki
27

Función simple para verificar esto:

function isArray(object)
{
    return object.constructor === Array;
}
MedianocheTortoise
fuente
16
Lo reduciría a una línea return object.constructor === Array, pero ¿estás seguro de que esto solo será cierto para las matrices?
mpen
12
Puede hacer eso con todas las expresiones booleanas. Me if(x) return true; else return falsevuelve loco cuando veo :-) Incluso si es al revés, debes negar la expresión.
mpen
3
La razón por la que esto no devuelve verdadero para getElementsByTagName, es porque el resultado de esa función es en realidad una colección HTMLC y no una matriz.
Yuval A.
66
Esto falla gravemente si el objeto no está definido o es nulo.
John Henckel
1
@JohnHenckel Vea mi respuesta stackoverflow.com/a/29400289/34806 toma en cuenta tanto su preocupación como el primer comentario, todo en una línea
Dexygen,
17

Como dice MDN aquí :

use Array.isArray u Object.prototype.toString.call para diferenciar objetos regulares de matrices

Me gusta esto:

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

  • Array.isArray(arr)

ajax333221
fuente
17

Solo hay una solución de línea para esta pregunta

x instanceof Array

donde x es la variable, devolverá verdadero si x es una matriz y falso si no lo es.

Vikash Kumar
fuente
¡Mucho más limpio y seguro para el futuro! Esto o una typeofcomparación.
ChristoKiwi
¿Es esto algo que recibe una buena cantidad de soporte de navegador? Me gusta.
Dan Zuzevich
1
Desafortunadamente, esto no es realmente útil sin un try / catch porque si "x" es un objeto como {}una matriz, entonces se obtiene un error de sintaxis.
abalter
15

Puede verificar el tipo de su variable si es una matriz con;

var myArray=[];

if(myArray instanceof Array)
{
....
}
Ahmet DAL
fuente
1
Algunas personas ya han mencionado instanceof... Creo que falla bajo algunos escenarios extraños.
mpen
15

Haría una función para probar el tipo de objeto con el que está tratando ...

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

entonces puedes escribir una declaración if simple ...

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

Hago esto de una manera muy simple. Funciona para mi. ¿Algún inconveniente?

Array.prototype.isArray = true;

a=[]; b={};
a.isArray  // true
b.isArray  // (undefined -> false)
rsbkk
fuente
77
engañado por{isArray:true}
Bergi
JSON.parse(someDataFromElsewhere).items.isArraypodría devolver verdadero (dependiendo de los datos) y romper su código.
Roy Tinker
12

Este es mi intento de mejorar esta respuesta teniendo en cuenta los comentarios:

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

Elimina el if / else, y explica la posibilidad de que la matriz sea nula o indefinida

Dexygen
fuente
constructor no está disponible en ES5
TechTurtle
11

He actualizado el violín jsperf con dos métodos alternativos, así como la comprobación de errores.

Resulta que el método que define un valor constante en los prototipos 'Objeto' y 'Matriz' es más rápido que cualquiera de los otros métodos. Es un resultado algo sorprendente.

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

Estos dos métodos no funcionan si la variable toma el valor indefinido, pero funcionan si está seguro de que tienen un valor. Con respecto a la verificación teniendo en cuenta el rendimiento si un valor es una matriz o un valor único, el segundo método parece un método rápido válido. Es ligeramente más rápido que 'instanceof' en Chrome, dos veces más rápido que el segundo mejor método en Internet Explorer, Opera y Safari (en mi máquina).

dejar op
fuente
9

Sé que la gente está buscando algún tipo de enfoque de JavaScript sin formato. Pero si quiere pensar menos, eche un vistazo aquí: http://underscorejs.org/#isArray

_.isArray(object) 

Devuelve verdadero si el objeto es una matriz.

(function(){ return _.isArray(arguments); })();
=> false
_.isArray([1,2,3]);
=> true
Eugene
fuente
77
"A menos que también se incluya otra etiqueta para un marco / biblioteca, se espera una respuesta pura de JavaScript".
Michał Perłakowski
5

La mejor solución que he visto es un reemplazo entre navegadores para typeof. Comprueba la solución de Angus Croll aquí .

La versión TL; DR está a continuación, pero el artículo es una gran discusión sobre el tema, por lo que debe leerlo si tiene tiempo.

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
fuente
5

Aquí está mi enfoque perezoso:

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

// ...

var test = [],
    wat = {};

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

Sé que es un sacrilegio "meterse" con el prototipo, pero parece funcionar significativamente mejor que el toStringmétodo recomendado .

Nota: Una trampa de este enfoque es que no funcionará más allá de los iframelímites , pero para mi caso de uso esto no es un problema.

namuol
fuente
ya no es mejor en términos de rendimiento, al menos en FF30 en Ubuntu de 64 bits
test30
2
engañado por los wat = {array_: true}objetos.
Bergi
@ Bergi: Sí, eso debería ser obvio. Si estás configurando obj.array_ = true, entonces solo te estás engañando a ti mismo .
namuol
@namuol: No necesariamente me estoy engañando a mí mismo. A menudo se utilizan suficientes objetos como diccionarios. Piense en un cacheobjeto para memorizar resultados de búsqueda que use las cadenas de búsqueda como claves de propiedad. ¿Qué pasa si un usuario busca array_? ¿Su objeto se convierte en una matriz debido a eso? Es solo un error.
Bergi
@namuol: Además, este enfoque requeriría que todas las partes involucradas (incluidas las bibliotecas usadas) puedan aceptar que .array_se usa para etiquetar matrices. Ese no es realmente el caso aquí, .arraypuede significar cualquier cosa. Al menos debe usar una cadena descriptiva y señalar la inadecuación del uso arbitrario, por ejemplo, con .__isArray = true.
Bergi
5

Hay un buen ejemplo en el libro Patrones JavaScript de Stoyan Stefanov que supone manejar todos los problemas posibles y utilizar el método ECMAScript 5 Array.isArray () .

Asi que aqui esta:

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

Por cierto, si está usando jQuery, puede usar su método $ .isArray ()

Salvador Dalí
fuente
2
+1: ¿por qué no solo un simple if(!Array.isArray) {...?
Marco Demaio
5

La forma más fácil y rápida de verificar si un objeto es una matriz o no.

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

o

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

o puedes hacer una función de utilidad:

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

uso:

isArray(arr); //return true
sheelpriy
fuente
5

Lo siguiente podría usarse si sabe que su objeto no tiene un método concat.

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

yesil
fuente
Este es un buen truco, pero podría ser anulado ... pero la mayoría de las veces debería obtener el resultado
Alireza
5

Podrías es el método de matriz, pero preferiría consultar con

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

ACERO
fuente
¿Por qué preferirías esto?
mpen
@mpen Object.getPrototypeOf(yourvariable)devuelve el prototipo de un objeto Array. Y el código es más rápido y seguro.
STEEL
1
Es fácil frustrar: pastebin.com/MP8d5bCE Además, ¿tiene pruebas de rendimiento para respaldar su reclamo "más rápido"?
mpen
4

Si los únicos dos tipos de valores que podrían pasarse a esta función son una cadena o una matriz de cadenas, manténgalo simple y use una typeofverificación para la posibilidad de la cadena:

function someFunc(arg) {
    var arr = (typeof arg == "string") ? [arg] : arg;
}
Tim Down
fuente
Sí ... eso funcionaría para este escenario, pero no en general. Terminé usando varargs de todos modos. :)
mpen
4
A = [1,2,3]
console.log(A.map==[].map)

En la búsqueda de la versión más corta, esto es lo que obtuve hasta ahora.

Tenga en cuenta que no existe una función perfecta que siempre detecte todas las combinaciones posibles. Es mejor conocer todas las habilidades y limitaciones de sus herramientas que esperar una herramienta mágica.

exebook
fuente
1
ligera derivación mía, A.map !== undefinedpero sí, eso podría ser un camino resbaladizo en el mundo de los patchers de mono;)
dmi3y
FYI: Esto no funciona en 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
fuente
4

Una función simple para probar si un valor de entrada es una matriz es la siguiente:

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

Esto funciona en varios navegadores y con navegadores más antiguos. Esto se extrae de la publicación del blog de TJ Crowders

Brad Parks
fuente
4

Puedes probar esto:

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
fuente
4

Esta función convertirá casi cualquier cosa en una matriz:

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

Utiliza algunas características más nuevas del navegador, por lo que es posible que desee rellenar esto para obtener el máximo soporte.

Ejemplos:

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

Las cadenas NB se convertirán en una matriz con un solo elemento en lugar de una matriz de caracteres. Elimine el isStringcheque si lo prefiere al revés.

Lo he usado Array.isArrayaquí porque es el más robusto y también el más simple.

mpen
fuente
4

En su caso, puede usar el concatmétodo de matriz que puede aceptar objetos individuales, así como matriz (e incluso combinados):

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 parece ser uno de los métodos más antiguos de Array (incluso IE 5.5 lo sabe bien).

kolyaseg
fuente