Como detectar se uma variável é um array

Qual é o melhor método padrão de navegador cruzado para determinar se uma variável em JavaScript é uma matriz ou não?

Pesquisando na web, há várias sugestões diferentes, algumas boas e algumas inválidas.

Por exemplo, o seguinte é uma abordagem básica:

function isArray(obj) { return (obj && obj.length); } 

No entanto, observe o que acontece se a matriz estiver vazia ou obj realmente não for uma matriz, mas implementar uma propriedade de comprimento, etc.

Então, qual implementação é a melhor em termos de trabalho real, ser cross-browser e ainda ter um desempenho eficiente?

A verificação de tipos de objects no JS é feita via instanceof , ou seja,

 obj instanceof Array 

Isso não funcionará se o object for passado pelos limites do quadro, já que cada quadro possui seu próprio object Array . Você pode contornar isso verificando a propriedade interna [[Class]] do object. Para obtê-lo, use Object.prototype.toString() (é garantido que isso funcione pelo ECMA-262):

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

Ambos os methods funcionarão apenas para matrizes reais e não para objects do tipo matriz, como o object de arguments ou as listas de nós. Como todos os objects do tipo array devem ter uma propriedade de length numérico, eu verificaria estes da seguinte forma:

 typeof obj !== 'undefined' && obj !== null && typeof obj.length === 'number' 

Observe que as strings passarão nessa verificação, o que pode causar problemas, pois o IE não permite access aos caracteres de uma string por índice. Portanto, você pode querer alterar typeof obj !== 'undefined' para typeof obj === 'object' para excluir primitivos e objects de host com tipos diferentes de 'object' . Isso ainda permitirá que objects de string passem, o que teria que ser excluído manualmente.

Na maioria dos casos, o que você realmente quer saber é se é possível fazer uma iteração no object por meio de índices numéricos. Portanto, pode ser uma boa ideia verificar se o object possui uma propriedade chamada 0 , o que pode ser feito por meio de uma dessas verificações:

 typeof obj[0] !== 'undefined' // false negative for `obj[0] = undefined` obj.hasOwnProperty('0') // exclude array-likes with inherited entries '0' in Object(obj) // include array-likes with inherited entries 

O casting para o object é necessário para funcionar corretamente para primitivos tipo array (ou seja, seqüências de caracteres).

Aqui está o código para verificações robustas de matrizes JS:

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

e iteráveis ​​(isto é, não vazios) objects semelhantes a matrizes:

 function isNonEmptyArrayLike(obj) { try { // don't bother with `typeof` - just access `length` and `catch` return obj.length > 0 && '0' in Object(obj); } catch(e) { return false; } } 

A chegada do ECMAScript 5th Edition nos dá o método mais seguro de testar se uma variável é uma matriz, Array.isArray () :

 Array.isArray([]); // true 

Embora a resposta aceita aqui funcione em frameworks e janelas para a maioria dos navegadores, ela não é para o Internet Explorer 7 e inferior , porque Object.prototype.toString chamado em uma matriz de uma janela diferente retornará [object Object] , não [object Array] . O IE 9 parece ter regredido a esse comportamento também (consulte a correção atualizada abaixo).

Eu não vou entrar em todas as partes essenciais da solução aqui, se você estiver interessado em ler este post no blog . No entanto, se você quiser uma solução que funcione em todos os navegadores, poderá usar:

 (function () { var toString = Object.prototype.toString, strArray = Array.toString(), jscript = /*@cc_on @_jscript_version @*/ +0; // jscript will be 0 for browsers other than IE if (!jscript) { Array.isArray = Array.isArray || function (obj) { return toString.call(obj) == "[object Array]"; } } else { Array.isArray = function (obj) { return "constructor" in obj && String(obj.constructor) == strArray; } } })(); 

Não é totalmente inquebrável, mas só seria quebrado por alguém que se esforçasse para quebrá-lo. Ele trabalha em torno dos problemas no IE7 e inferior e no IE9. O bug ainda existe no IE 10 PP2 , mas pode ser corrigido antes do lançamento.

PS, se você não tiver certeza sobre a solução, então eu recomendo que você teste o conteúdo do seu coração e / ou leia a postagem do blog. Existem outras soluções possíveis se você não estiver à vontade usando a compilation condicional.

Crockford tem duas respostas na página 106 de “The Good Parts”. O primeiro verifica o construtor, mas fornecerá falsos negativos em diferentes frameworks ou janelas. Aqui está o segundo:

 if (my_value && typeof my_value === 'object' && typeof my_value.length === 'number' && !(my_value.propertyIsEnumerable('length')) { // my_value is truly an array! } 

Crockford ressalta que esta versão irá identificar o array de arguments como um array, mesmo que não tenha nenhum dos methods de array.

Sua interessante discussão sobre o problema começa na página 105.

Há outra discussão interessante (post-Good Parts) aqui que inclui esta proposta:

 var isArray = function (o) { return (o instanceof Array) || (Object.prototype.toString.apply(o) === '[object Array]'); }; 

Toda a discussão faz com que eu nunca queira saber se algo é ou não uma matriz.

jQuery implementa uma function isArray, que sugere que a melhor maneira de fazer isso é

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

(fragment retirado do jQuery v1.3.2 – ligeiramente ajustado para fazer sentido fora do contexto)

Roubando do guru John Resig e jquery:

 function isArray(array) { if ( toString.call(array) === "[object Array]") { return true; } else if ( typeof array.length === "number" ) { return true; } return false; } 

O que você vai fazer com o valor depois de decidir que é um array?

Por exemplo, se você pretende enumerar os valores contidos se ele se parece com uma matriz OU se é um object sendo usado como uma tabela de hash, o código a seguir obtém o que você deseja (esse código pára quando a function de fechamento retorna qualquer outra do que “undefined”. Observe que ele não itera em contêineres ou enumerações COM; isso é deixado como um exercício para o leitor):

 function iteratei( o, closure ) { if( o != null && o.hasOwnProperty ) { for( var ix in seq ) { var ret = closure.call( this, ix, o[ix] ); if( undefined !== ret ) return ret; } } return undefined; } 

(Nota: “o! = Null” testa tanto para null como para indefinido)

Exemplos de uso:

 // Find first element who's value equals "what" in an array var b = iteratei( ["who", "what", "when" "where"], function( ix, v ) { return v == "what" ? true : undefined; }); // Iterate over only this objects' properties, not the prototypes' function iterateiOwnProperties( o, closure ) { return iteratei( o, function(ix,v) { if( o.hasOwnProperty(ix) ) { return closure.call( this, ix, o[ix] ); } }) } 

Se você quiser cross-browser, você quer jQuery.isArray .

Na escola, há um exemplo que deveria ser bastante normal.

Para verificar se uma variável é uma matriz, eles usam algo semelhante a esta

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

testado no Chrome, Firefox, Safari, ie7

Se você está fazendo isso no CouchDB (SpiderMonkey), então use

Array.isArray(array)

como array.constructor === Array ou array instanceof Array não funcionam. Usar array.toString() === "[object Array]" funciona, mas parece bastante desonesto em comparação.

Uma das melhores versões pesquisadas e discutidas desta function pode ser encontrada no site do PHPJS . Você pode vincular a pacotes ou você pode ir diretamente para a function . Eu recomendo altamente o site por equivalentes bem construídos de funções PHP em JavaScript.

Não é suficiente referência igual de construtores. Às vezes eles têm referências diferentes de construtor. Então eu uso representações de string deles.

 function isArray(o) { return o.constructor.toString() === [].constructor.toString(); } 

Substitua Array.isArray(obj) por obj.constructor==Array

amostras:

Array('44','55').constructor==Array return true (IE8 / Chrome)

'55'.constructor==Array retorna falso (IE8 / Chrome)