Como verificar se um objeto é uma matriz?


2753

Estou tentando escrever uma função que aceita uma lista de seqüências de caracteres ou uma única seqüência de caracteres. Se for uma string, quero convertê-la em uma matriz com apenas um item, para que eu possa fazer um loop sobre ela sem medo de erro.

Então, como verifico se a variável é uma matriz?


Reuni as várias soluções abaixo e criei um teste jsperf . Eles são todos rápidos, portanto, basta usar Array.isArray- ele é bem suportado agora e funciona em vários quadros .


6
Eu pensei que você queria 'verificar se o objeto é uma matriz', mas você deseja verificar se 'objeto é uma matriz de seqüências de caracteres ou uma única sequência' especificamente. Não tem certeza se você vê? Ou é só comigo? Eu estava pensando em algo mais como este ... sou eu quem está perdendo alguma coisa aqui?
— Rd1g0

149
TL; DR - arr.constructor === Arrayé o mais rápido.
— Neta

3
jsben.ch/#/QgYAV - uma referência para as formas mais comuns
— EscapeNetscape

39
TL; DR - matriz. isArray (arr) desde ES5; e $. isArray (arr) no jQuery.
— Ondra Žižka

6
Lembre-se de que, se por algum motivo você sobrescrever seu construtor via protótipo, esse arr.constructor === Arrayteste retornará falso. Array.isArray(arr)ainda retorna verdadeiro embora.
— Ghaschel

Respostas:


979

Nos navegadores modernos, você pode fazer

Array.isArray(obj)

( Suportado pelo Chrome 5, Firefox 4.0, IE 9, Opera 10.5 e Safari 5)

Para compatibilidade com versões anteriores, você pode adicionar o seguinte

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

Se você usa jQuery, pode usar jQuery.isArray(obj)ou $.isArray(obj). Se você usar sublinhado, poderá usar_.isArray(obj)

Se você não precisa detectar matrizes criadas em quadros diferentes, também pode usar instanceof

obj instanceof Array

9
Aqui está uma mais completa lista de navegadores que suportamArray.isArray
— lightswitch05

if (typeof Array.isArray === 'undefined') {pode ser alterado paraif(!Array.isArray) {
— iMatoria 21/05

Pois o que vale a pena Object.prototype.string.call(obj)pode ser falsificado se o objeto Symbol.toStringTagestiver nele. Dito isto, não conheço nenhum ambiente que seja enviado, Symbol.toStringTagmas não, Array.isArrayportanto isso parece seguro.
— Benjamin Gruenbaum

5
Por que instanceof Arrayfalha se a matriz é de um quadro diferente?
— NobleUplift

16
@NobleUplift: instanceof Arrayfalha se a matriz for de um quadro diferente porque cada matriz desse quadro diferente possui um Arrayconstrutor e um protótipo diferentes . Por motivos de compatibilidade / segurança, todos os quadros têm seu próprio ambiente global e isso inclui objetos globais. O Objectglobal de um quadro é diferente do Objectglobal de outro. O mesmo Arrayvale para os globais. Axel Rauschmayer fala mais sobre isso .
— jschoi

1943

O método fornecido no padrão ECMAScript para encontrar a classe de Object é usar o toStringmétodo de Object.prototype.

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

Ou você pode usar typeofpara testar se é uma String:

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

Ou, se você não está preocupado com o desempenho, basta fazer um concatpara uma nova matriz vazia.

someVar = [].concat( someVar );

Há também o construtor que você pode consultar diretamente:

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

Confira um tratamento completo no blog de @TJ Crowder , conforme publicado em seu comentário abaixo.

Confira este benchmark para ter uma idéia de qual método tem melhor desempenho: http://jsben.ch/#/QgYAV

De @Bharath, converta string em array usando Es6 para a pergunta:

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

suponha:

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 Sim, toStringé um dos caminhos a seguir. Eu faço um pouco de um resumo aqui: blog.niftysnippets.org/2010/09/say-what.html
— TJ Crowder

3
typeof new String('beans') > 'objeto'
— Ben

16
Se você não quiser digitar "[array de objetos]", use Object.prototype.toString.call (someVar) === Object.prototype.toString.call ([]) ou crie uma função de conveniência para obter o tipo, se você não 't deseja digitar Object.prototype.toString.call
— Pramod

13
Eu uso o vanilla Array.isArray, que funciona em 'navegadores modernos' (ou seja, IE9 + e todos os outros). E, para suporte a navegadores antigos, use o shim do MDN developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/…
— David Gilbertson

21
Vive no mundo moderno - #Array.isArray(obj)
— 123515 mcfedr

1274

Primeiro, verificaria se sua implementação suporta isArray:

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

Você também pode tentar usar o instanceofoperador

v instanceof Array

127
v instanceof Arrayretornará false se vfoi criado em outro quadro ( vé instância da thatFrame.contentWindow.Arrayclasse).
— precisa saber é

47
Para ser específico: Array.isArrayé definido como parte do ECMAScript 5 / Javascript 1.8.5.
— Jevon

8
Solução realmente simples e limpa, MAS o isArray não é compatível com alguns navegadores mais antigos (ex IE7 e IE8). Fonte: kangax.github.io/es5-compat-table/#
— Wookie88

2
Que tal: if (Array.isArray) retornar Array.isArray (v); else return v instância de Array;
— Lewdev

1
ou apenas:return (Array.isArray && Array.isArray(v)) || (v instanceof Array);
— Stijn de Witt

298

O jQuery também oferece um $.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>


27
Apenas uma nota, jQuery usa o método toString internamente: GitHub Fonte
— Jacob Squires

5
@JacobSquires depende. Acabei de testar aqui, o jQuery mais recente no Chrome - $.isArray === Array.isArrayestá retornando verdadeiro.
— Renan

3
@ Renan: Esta é a coisa boa sobre o uso do jQuery. Ele geralmente usa o método mais moderno e melhor para fazê-lo, e você não precisa fazer todo o recurso verificando a si mesmo para saber o que usar.
— temor

jQuery está usando Array.isArraynos bastidores: github.com/jquery/jquery/blob/master/src/core.js#L211
— Sergiu

1
Mas ninguém vai usar o jQuery APENAS PARA essa funcionalidade, certo? Eu não apenas baixaria o jquery porque quero verificar se algo é uma matriz: p
— Automagisch

106

Este é o mais rápido entre todos os métodos (todos os navegadores suportados):

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

2
Você está certo, esse é o mais rápido de acordo com os testes que incluí na pergunta.
— MPEN

5
Existem desvantagens em usar esse método? Parece muito mais simples e eficaz do que a resposta top aceita.
— David Meza

@ shinobi - apenas curioso (e eu já vi isso frequentemente) - por que você expressa a condição if (obj && Array === obj.constructor)em vez de if (obj && obj.constructor === Array)? Está perdido na tradução para o inglês e depois no código? por exemplo, os falantes de inglês geralmente tendem a perguntar "o objeto existe e seu construtor vem da classe da matriz?", portanto o código flui ao lê-lo é mais lógico. ou existe algum motivo técnico?
— não sincronizado

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();}
— não sincronizado

3
@shinobi tudo de bom. Suponho que possa ser uma ressaca de um hábito c seguro - se você usar acidentalmente = em vez disso ==, ele não será compilado, pois não é uma variável atribuível.
— não sincronizado

47

Imagine que você tem esta matriz abaixo :

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

Javascript (navegadores novos e antigos):

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

então chame assim:

isArray(arr);

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

Array.isArray(arr);

jQuery:

$.isArray(arr);

Angular:

angular.isArray(arr);

Sublinhado e Lodash:

_.isArray(arr);

34

Array.isArray funciona rápido, mas não é suportado por todas as versões dos navegadores. Então você pode fazer uma exceção para outras pessoas e usar o método universal:

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

3
Você precisa obter o .toString()método Object.prototype. No momento, você está usando o window.toString(), que não é o mesmo.
— o sistema

Você está certo. window.toStringfaça o mesmo que Object.prototype.toStringapenas no Chrome.
— CruorVult

O isArray não é nada rápido. É o método mais lento.
— jemiloii

Por que não adicioná-lo ao Array em vez de Utils? (Eu sei que você não quer propriedades extras sobre novos objetos de matriz, mas acho que só acontece se você adicionar IsArray para Array.prototype.)
— David Winiecki

27

Função simples para verificar isso:

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

16
Eu reduziria isso para uma linha return object.constructor === Array- mas você tem certeza de que isso só retornará verdadeiro para matrizes?
— fácil

12
Pode fazer isso com todas as expressões booleanas. Me deixa louco quando vejo if(x) return true; else return false:-) Mesmo que seja ao contrário, você deve negar a expressão.
— fácil

3
A razão pela qual isso não retorna true para getElementsByTagName, é porque o resultado dessa função é realmente um HTMLCollection e não uma matriz.
— Yuval A.

6
Isso falhará se o objeto for indefinido ou nulo.
— 21715 John Henckel

1
@JohnHenckel Veja a minha resposta stackoverflow.com/a/29400289/34806 que leva em conta tanto a sua preocupação, bem como o primeiro comentário, tudo na mesma linha
— Dexygen

17

Como a MDN diz aqui :

use Array.isArray ou Object.prototype.toString.call para diferenciar objetos regulares de matrizes

Como isso:

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

  • Array.isArray(arr)


17

Existe apenas uma solução de linha para esta pergunta

x instanceof Array

onde x é a variável, retornará true se x for uma matriz e false se não for.


Muito mais limpo e seguro para o futuro! Isso ou uma typeofcomparação.
— ChristoKiwi

Isso é algo que recebe uma boa quantidade de suporte ao navegador? Eu gosto disso.
— Dan Zuzevich 20/08/19

1
Infelizmente, isso não é realmente útil sem uma tentativa / captura, porque se "x" é um objeto como {}uma matriz, você recebe um erro de sintaxe.
— Abalter)

15

Você pode verificar o tipo de sua variável se é uma matriz com;

var myArray=[];

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

1
Algumas pessoas já mencionaram instanceof.. Acho que falha em alguns cenários estranhos.
— MPEN

15

Eu faria uma função para testar o tipo de objeto com o qual você está lidando ...

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

então você pode escrever uma declaração if simples ...

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

12

Eu faço isso de uma maneira muito simples. Funciona para mim. Alguma desvantagem?

Array.prototype.isArray = true;

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

7
enganado por{isArray:true}
— Bergi

JSON.parse(someDataFromElsewhere).items.isArraypode retornar true (dependendo dos dados) e quebrar seu código.
— Roy Tinker

12

Esta é minha tentativa de melhorar esta resposta, levando em consideração os comentários:

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

Ele se livra do if / else e explica a possibilidade de o array ser nulo ou indefinido


construtor não está disponível em ES5
— TechTurtle


11

Atualizei o jsperf fiddle com dois métodos alternativos, bem como com a verificação de erros.

Acontece que o método que define um valor constante nos protótipos 'Objeto' e 'Matriz' é mais rápido que qualquer outro método. É um resultado um tanto surpreendente.

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

Esses dois métodos não funcionam se a variável receber o valor indefinido, mas funcionarão se você tiver certeza de que eles têm um valor. Com relação à verificação com o desempenho em mente se um valor é uma matriz ou um valor único, o segundo método se parece com um método rápido válido. É um pouco mais rápido que 'instanceof' no Chrome, duas vezes mais rápido que o segundo melhor método no Internet Explorer, Opera e Safari (na minha máquina).


9

Eu sei que as pessoas estão procurando algum tipo de abordagem javascript bruta. Mas se você quiser pensar menos, dê uma olhada aqui: http://underscorejs.org/#isArray

_.isArray(object) 

Retorna true se o objeto for uma matriz.

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

7
"A menos que outra tag para uma estrutura / biblioteca também esteja incluída, é esperada uma resposta JavaScript pura."
— Michał Perłakowski

5

A melhor solução que eu vi é uma substituição entre navegadores do typeof. Confira a solução da Angus Croll aqui .

A versão TL; DR está abaixo, mas o artigo é uma ótima discussão sobre o problema; portanto, você deve lê-lo se tiver tempo.

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

Aqui está minha abordagem preguiçosa:

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

// ...

var test = [],
    wat = {};

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

Sei que é um sacrilégio "mexer com" o protótipo, mas ele parece ter um desempenho significativamente melhor que o toStringmétodo recomendado .

Nota: Uma armadilha dessa abordagem é que ela não funcionará além dos iframelimites , mas para o meu caso de uso isso não é um problema.


não é mais melhor em termos de desempenho, pelo menos no FF30 no Ubuntu de 64 bits
— test30

2
enganado por wat = {array_: true}objetos.
— Bergi 7/08/2015

@ Bergi: Sim, isso deve ser óbvio. Se você estiver se preparando obj.array_ = true, estará apenas se enganando .
— namuol

@namuol: Eu não estou necessariamente me enganando. Geralmente, objetos suficientes são usados ​​como dicionários. Pense em um cacheobjeto para memorizar os resultados da pesquisa que usa as cadeias de pesquisa como chaves de propriedade. E se um usuário pesquisar array_? Seu objeto se torna uma matriz por causa disso? É apenas um bug.
— Bergi 08/08/2015

@namuol: Além disso, essa abordagem exigiria que todas as partes envolvidas (incluindo as bibliotecas usadas) possam concordar que .array_é usado para marcar matrizes. Isso realmente não é o caso aqui, .arraypode significar qualquer coisa. Você deve pelo menos usar uma sequência descritiva e sinalizar inadequação de uso arbitrário, por exemplo, com .__isArray = true.
— Bergi 08/08/2015

5

Há um bom exemplo no livro JavaScript Patterns, de Stoyan Stefanov, que supõe lidar com todos os problemas possíveis, além de utilizar o método Array.isArray () do ECMAScript 5 .

Então aqui está:

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

A propósito, se você estiver usando jQuery, poderá usar o método $ .isArray ()


2
+1: por que não apenas um simples if(!Array.isArray) {...?
— Marco Demaio

5

A maneira mais fácil e rápida de verificar se um Objeto é uma Matriz ou não.

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

ou

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

ou você pode fazer uma função de utilitário:

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

uso:

isArray(arr); //return true

5

O seguinte pode ser usado se você souber que seu objeto não possui um método concat.

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


Este é um truque bom, mas poderia ser substituído ... mas na maioria das vezes deve obter o resultado
— Alireza

5

Você poderia é o método isArray, mas eu preferiria verificar com

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


Por que você prefere isso?
— MPEN

@mpen Object.getPrototypeOf(yourvariable)retorna o protótipo de um objeto Array. E o código é mais rápido e seguro.
— STEEL

1
É fácil frustrar: pastebin.com/MP8d5bCE Além disso, você tem testes de desempenho para fazer backup de sua reivindicação "mais rápida"?
— MPEN

4

Se os únicos dois tipos de valores que podem ser passados ​​para essa função são uma sequência ou uma matriz de sequências, mantenha-a simples e use uma typeofverificação da possibilidade de sequência:

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

Sim ... isso funcionaria para esse cenário, mas não em geral. Acabou usando varargs de qualquer maneira. :)
— MPEN

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

Em busca da versão mais curta, aqui está o que eu consegui até agora.

Observe que não existe uma função perfeita que sempre detecte todas as combinações possíveis. É melhor conhecer todas as habilidades e limitações de suas ferramentas do que esperar uma ferramenta mágica.


1
ligeira derivação da mina A.map !== undefined, mas sim, que poderia ser estrada escorregadio no mundo do macaco patchers;)
— dmi3y

FYI: Isso não funciona entre os 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

Uma função simples para testar se um valor de entrada é uma matriz é o seguinte:

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

Isso funciona em vários navegadores e com navegadores mais antigos. Isso é retirado da postagem do blog de TJ Crowders


4

Você pode tentar isso:

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

Esta função transformará quase tudo em uma 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]"
}

Ele usa alguns recursos mais recentes do navegador, portanto, você pode preencher isso para obter o máximo suporte.

Exemplos:

> 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 seqüências serão convertidas em uma matriz com um único elemento em vez de uma matriz de caracteres. Exclua a isStringverificação se você preferir o contrário.

Eu usei Array.isArrayaqui porque é o mais robusto e também o mais simples.


4

No seu caso, você pode usar o concatmétodo Array, que pode aceitar objetos únicos e também array (e até combinado):

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 um dos métodos mais antigos do Array (até o IE 5.5 o conhece bem).

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.