Como você verifica se uma variável é uma matriz em JavaScript?

Gostaria de verificar se uma variável é uma matriz ou um valor único em JavaScript.

Eu encontrei uma solução possível …

if (variable.constructor == Array)... 

Essa é a melhor maneira de fazer isso?

Existem várias maneiras de verificar se uma variável é uma matriz ou não. A melhor solução é aquela que você escolheu.

 variable.constructor === Array 

Esse é o método mais rápido no Chrome e, provavelmente, em todos os outros navegadores. Todas as matrizes são objects, portanto, verificar a propriedade do construtor é um processo rápido para mecanismos JavaScript.

Se você está tendo problemas em descobrir se uma propriedade de objects é uma matriz, primeiro verifique se a propriedade está lá.

 variable.prop && variable.prop.constructor === Array 

Algumas outras maneiras são:

 variable instanceof Array 

Esse método executa cerca de 1/3 da velocidade como o primeiro exemplo. Ainda é bastante sólido, parece mais limpo, se você é tudo sobre código bonito e não tanto sobre o desempenho. Observe que a verificação de números não funciona como variable instanceof Number sempre retorna false . Update: instanceof agora vai 2/3 da velocidade!

 Array.isArray(variable) 

Este último é, na minha opinião, o mais feio e é um dos mais lentos. Correndo cerca de 1/5 da velocidade como o primeiro exemplo. Array.prototype, é na verdade uma matriz. você pode ler mais sobre isso aqui https://developer.mozilla.org/pt-BR/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray

Então, mais uma atualização

 Object.prototype.toString.call(variable) === '[object Array]'; 

Esse cara é o mais lento para tentar verificar um Array. No entanto, este é um balcão único para qualquer tipo que você está procurando. No entanto, como você está procurando por um array, basta usar o método mais rápido acima.

Além disso, eu corri alguns testes: http://jsperf.com/instanceof-array-vs-array-is-ray/33 Então, se divertir e confira.

Nota: o @EscapeNetscape criou outro teste quando o jsperf.com está inativo. http://jsben.ch/#/QgYAV Eu queria ter certeza de que o link original permanecesse sempre que o jsperf estivesse online novamente.

Você também pode usar:

 if (value instanceof Array) { alert('value is Array!'); } else { alert('Not an array'); } 

Isto parece-me uma solução bastante elegante, mas para cada um deles.

Editar:

A partir do ES5 existe agora também:

 Array.isArray(value); 

Mas isso vai quebrar em navegadores mais antigos, a menos que você esteja usando polyfills (basicamente … IE8 ou similar).

Eu notei que alguém mencionou o jQuery, mas eu não sabia que havia uma function isArray() . Acontece que foi adicionado na versão 1.3.

jQuery implementa como Peter sugere:

 isArray: function( obj ) { return toString.call(obj) === "[object Array]"; }, 

Tendo acreditado muito no jQuery (especialmente em suas técnicas de compatibilidade entre navegadores) eu atualizarei para a versão 1.3 e usarei sua function (desde que a atualização não cause muitos problemas) ou use este método sugerido diretamente na minha código.

Muito obrigado pelas sugestões.

Existem várias soluções com todas as suas peculiaridades. Esta página fornece uma boa visão geral. Uma solução possível é:

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

Nos navegadores modernos (e alguns navegadores herdados), você pode fazer

 Array.isArray(obj) 

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

Se você precisar dar suporte a versões mais antigas do IE, você pode usar es5-shim para polyfill Array.isArray; ou adicione 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ê usar jQuery, poderá usar jQuery.isArray(obj) ou $.isArray(obj) . Se você usar sublinhado, você pode usar _.isArray(obj)

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

 obj instanceof Array 

Nota : a palavra-chave arguments que pode ser usada para acessar o argumento de uma function não é um Array, mesmo que (normalmente) se comporte como um:

 var func = function() { console.log(arguments) // [1, 2, 3] console.log(arguments.length) // 3 console.log(Array.isArray(arguments)) // false !!! console.log(arguments.slice) // undefined (Array.prototype methods not available) console.log([3,4,5].slice) // function slice() { [native code] } } func(1, 2, 3) 

Esta é uma pergunta antiga, mas com o mesmo problema eu encontrei uma solução muito elegante que eu quero compartilhar.

Adicionando um protótipo para Array torna muito simples

 Array.prototype.isArray = true; 

Agora, uma vez, se você tiver um object que deseja testar para ver se é um array, tudo o que você precisa é verificar a nova propriedade

 var box = doSomething(); if (box.isArray) { // do something } 

isArray só está disponível se for um array

Via Crockford :

 function typeOf(value) { var s = typeof value; if (s === 'object') { if (value) { if (value instanceof Array) { s = 'array'; } } else { s = 'null'; } } return s; } 

A falha principal que Crockford menciona é a incapacidade de determinar corretamente matrizes que foram criadas em um contexto diferente, por exemplo, window . Essa página tem uma versão muito mais sofisticada, se isso for insuficiente.

Eu pessoalmente gosto da sugestão de Peter: https://stackoverflow.com/a/767499/414784 (para ECMAScript 3. Para o ECMAScript 5, use Array.isArray() )

Comentários no post indicam, no entanto, que se toString() for alterado, a maneira de verificar um array falhará. Se você realmente quer ser específico e ter certeza de que toString() não foi alterado, e não há problemas com o atributo de class de objects ( [object Array] é o atributo de class de um object que é um array), então eu recomendo fazer algo assim:

 //see if toString returns proper class attributes of objects that are arrays //returns -1 if it fails test //returns true if it passes test and it's an array //returns false if it passes test and it's not an array function is_array(o) { // make sure an array has a class attribute of [object Array] var check_class = Object.prototype.toString.call([]); if(check_class === '[object Array]') { // test passed, now check return Object.prototype.toString.call(o) === '[object Array]'; } else { // may want to change return value to something more desirable return -1; } } 

Note que em JavaScript The Definitive Guide 6ª edição, 7.10, ele diz que Array.isArray() é implementado usando Object.prototype.toString.call() no ECMAScript 5. Observe também que se você vai se preocupar com toString() ‘ Como a implementação está mudando, você também deve se preocupar com todos os outros methods incorporados. Por que usar o push() ? Alguém pode mudar isso! Tal abordagem é boba. A verificação acima é uma solução oferecida para aqueles preocupados com toString() mudando, mas acredito que o cheque é desnecessário.

Quando postei essa pergunta, a versão do JQuery que eu estava usando não incluía uma function isArray . Se tivesse, eu provavelmente teria usado apenas confiando que a implementação fosse a melhor maneira independente de executar essa verificação de tipo.

Como a JQuery agora oferece essa function, eu sempre a utilizo …

 $.isArray(obj); 

(a partir da versão 1.6.2) Ele ainda é implementado usando comparações em strings na forma

 toString.call(obj) === "[object Array]" 

Pensei em adicionar outra opção para aqueles que já podem estar usando a biblioteca Underscore.js em seu script. Underscore.js tem uma function isArray () (veja http://underscorejs.org/#isArray ).

 _.isArray(object) 

Retorna true se o object for uma matriz.

Se você está lidando apenas com o EcmaScript 5 e acima, então você pode usar a function Array.isArray embutida

por exemplo,

 Array.isArray([]) // true Array.isArray("foo") // false Array.isArray({}) // false 

Se você estiver usando Angular, você pode usar a function angular.isArray ()

 var myArray = []; angular.isArray(myArray); // returns true var myObj = {}; angular.isArray(myObj); //returns false 

http://docs.angularjs.org/api/ng/function/angular.isArray

No JavaScript de Crockford, The Good Parts , existe uma function para verificar se o argumento dado é um array:

 var is_array = function (value) { return value && typeof value === 'object' && typeof value.length === 'number' && typeof value.splice === 'function' && !(value.propertyIsEnumerable('length')); }; 

Ele explica:

Primeiro, perguntamos se o valor é verdadeiro. Fazemos isso para rejeitar valores nulos e outros valores falsos. Em segundo lugar, perguntamos se o tipo de valor é ‘object’. Isso será verdade para objects, matrizes e (estranhamente) nulo. Terceiro, perguntamos se o valor tem uma propriedade de comprimento que é um número. Isso sempre será verdadeiro para matrizes, mas geralmente não para objects. Quarto, perguntamos se o valor contém um método de emenda. Isso novamente será verdade para todos os arrays. Finalmente, perguntamos se a propriedade length é enumerável (o comprimento será produzido por um loop in?). Isso será falso para todos os arrays. Este é o teste mais confiável para arrayness que eu encontrei. É uma pena que seja tão complicado.

Eu estava usando esta linha de código:

 if (variable.push) { // variable is array, since AMAIK only arrays have push() method. } 

A solução universal está abaixo:

 Object.prototype.toString.call(obj)=='[object Array]' 

A partir do ECMAScript 5, uma solução formal é:

 Array.isArray(arr) 

Além disso, para bibliotecas antigas de JavaScript, você pode encontrar a solução abaixo, embora não seja preciso o suficiente:

 var is_array = function (value) { return value && typeof value === 'object' && typeof value.length === 'number' && typeof value.splice === 'function' && !(value.propertyIsEnumerable('length')); }; 

As soluções são de http://www.pixelstech.net/topic/85-How-to-check-wether-an-object-is-anarray-or-not-in-JavaScript

código referido em https://github.com/miksago/Evan.js/blob/master/src/evan.js

  var isArray = Array.isArray || function(obj) { return !!(obj && obj.concat && obj.unshift && !obj.callee);}; 

Para aqueles que codificam golfe, um teste não confiável com menos caracteres:

 function isArray(a) { return a.map; } 

Isso é comumente usado ao percorrer / achatar uma hierarquia:

 function golf(a) { return a.map?[].concat.apply([],a.map(golf)):a; } input: [1,2,[3,4,[5],6],[7,[8,[9]]]] output: [1, 2, 3, 4, 5, 6, 7, 8, 9] 

De w3schools :

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

Eu gostei da resposta de Brian:

 function is_array(o){ // make sure an array has a class attribute of [object Array] var check_class = Object.prototype.toString.call([]); if(check_class === '[object Array]') { // test passed, now check return Object.prototype.toString.call(o) === '[object Array]'; } else{ // may want to change return value to something more desirable return -1; } } 

mas você poderia apenas fazer assim:

 return Object.prototype.toString.call(o) === Object.prototype.toString.call([]); 

Eu criei este pequeno código, que pode retornar tipos verdadeiros.

Ainda não tenho certeza sobre o desempenho, mas é uma tentativa de identificar corretamente o tipo.

https://github.com/valtido/better-typeOf também blogou um pouco sobre isso aqui http://www.jqui.net/jquery/better-typeof-than-the-javascript-native-typeof/

funciona, semelhante ao tipo atual.

 var user = [1,2,3] typeOf(user); //[object Array] 

Acho que pode precisar de um pouco de ajuste fino, e levar em conta as coisas, eu não encontrei ou testei corretamente. Assim, outras melhorias são bem-vindas, seja em termos de desempenho ou de forma incorreta, na reimportação do typeOf.

Eu acho que usando myObj.constructor == Object e myArray.constructor == Array é o melhor caminho. É quase 20x mais rápido que usar toString (). Se você estender objects com seus próprios construtores e quiser que essas criações sejam consideradas “objects” da mesma forma, isso não funciona, mas, caso contrário, é mais rápido. typeof é tão rápido quanto o método construtor, mas typeof [] == ‘object’ retorna true, o que geralmente é indesejável. http://jsperf.com/constructor-vs-tostring

Uma coisa a notar é que null.constructor lançará um erro, então, se você estiver verificando valores nulos, terá que primeiro fazer if (testThing! == null) {}

Como a propriedade .length é especial para matrizes em javascript, você pode simplesmente dizer

 obj.length === +obj.length // true if obj is an array 

Underscorejs e várias outras bibliotecas usam este truque curto e simples.

Algo que acabei de inventar:

if (item.length) //This is an array else //not an array