Come si controlla se una variabile è una matrice in JavaScript?

Vorrei verificare se una variabile è o un array o un singolo valore in JavaScript.

Ho trovato una ansible soluzione …

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

È questo il modo migliore per farlo?

Esistono diversi modi per verificare se una variabile è un array o meno. La soluzione migliore è quella che hai scelto.

 variable.constructor === Array 

Questo è il metodo più veloce su Chrome e molto probabilmente su tutti gli altri browser. Tutti gli array sono oggetti, quindi il controllo della proprietà del costruttore è un processo veloce per i motori JavaScript.

Se si riscontrano problemi con la ricerca di una matrice di oggetti, è necessario innanzitutto verificare se la proprietà è presente.

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

Alcuni altri modi sono:

 variable instanceof Array 

Questo metodo esegue circa 1/3 della velocità come primo esempio. Ancora piuttosto solido, sembra più pulito, se si tratta di un bel codice e non tanto delle prestazioni. Si noti che il controllo dei numeri non funziona come variable instanceof Number restituisce sempre false . Aggiornamento: instanceof ora va 2/3 della velocità!

 Array.isArray(variable) 

Quest’ultimo è, a mio avviso il più brutto, ed è uno dei più lenti. Correndo a circa 1/5 della velocità come primo esempio. Array.prototype, è in realtà un array. puoi leggere maggiori informazioni qui https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray

Quindi ancora un altro aggiornamento

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

Questo ragazzo è il più lento per cercare di controllare una matrice. Tuttavia, questo è uno sportello unico per qualsiasi tipo che stai cercando. Tuttavia, dal momento che stai cercando un array, usa semplicemente il metodo più veloce sopra.

Inoltre, ho eseguito alcuni test: http://jsperf.com/instanceof-array-vs-array-isarray/33 Quindi divertiti e dai un’occhiata.

Nota: @EscapeNetscape ha creato un altro test poiché jsperf.com non è attivo. http://jsben.ch/#/QgYAV Volevo assicurarmi che il link originale rimanga valido ogni volta che jsperf torna online.

Puoi anche usare:

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

Questa mi sembra una soluzione piuttosto elegante, ma a ciascuno la sua.

Modificare:

A partire da ES5 ora c’è anche:

 Array.isArray(value); 

Ma questo si interromperà sui browser più vecchi, a meno che non si utilizzino i polyfill (fondamentalmente … IE8 o simili).

Ho notato che qualcuno ha menzionato jQuery, ma non sapevo che esistesse una funzione isArray() . Si scopre che è stato aggiunto nella versione 1.3.

jQuery lo implementa come suggerisce Peter:

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

Avendo già dato molta fiducia in jQuery (specialmente le loro tecniche per la compatibilità cross-browser), aggiornerò alla versione 1.3 e userei la loro funzione (ammesso che l’aggiornamento non causi troppi problemi) o usare questo metodo suggerito direttamente nella mia codice.

Molte grazie per i suggerimenti.

Ci sono più soluzioni con tutte le loro stranezze. Questa pagina offre una buona panoramica. Una ansible soluzione è:

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

Nei browser moderni (e in alcuni browser legacy), puoi farlo

 Array.isArray(obj) 

( Supportato da Chrome 5, Firefox 4.0, IE 9, Opera 10.5 e Safari 5)

Se è necessario supportare versioni precedenti di IE, è ansible utilizzare es5-shim in polyfill Array.isArray; o aggiungere il seguente

 # 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 usi jQuery puoi usare jQuery.isArray(obj) o $.isArray(obj) . Se usi il carattere di sottolineatura puoi usare _.isArray(obj)

Se non hai bisogno di rilevare array creati in frame diversi puoi anche solo usare instanceof

 obj instanceof Array 

Nota : la parola chiave arguments che può essere utilizzata per accedere all’argomento di una funzione non è una matrice, anche se (di solito) si comporta come una:

 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) 

Questa è una vecchia domanda, ma avendo lo stesso problema ho trovato una soluzione molto elegante che voglio condividere.

L’aggiunta di un prototipo alla matrice rende molto semplice

 Array.prototype.isArray = true; 

Ora una volta se hai un object che vuoi testare per vedere se è un array tutto ciò che serve è controllare la nuova proprietà

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

isArray è disponibile solo se è un 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; } 

Il principale fallimento di Crockford menziona l’incapacità di determinare correttamente gli array che sono stati creati in un contesto diverso, ad esempio, la window . Quella pagina ha una versione molto più sofisticata se questo è insufficiente.

Personalmente mi piace il suggerimento di Peter: https://stackoverflow.com/a/767499/414784 (per ECMAScript 3. Per ECMAScript 5, usa Array.isArray() )

I commenti sul post indicano, tuttavia, che se toString() viene completamente modificato, questo modo di controllare un array fallirà. Se vuoi essere specifico e assicurarti che toString() non sia stato modificato, e non ci siano problemi con l’attributo della class objects ( [object Array] è l’attributo di class di un object che è un array), allora ti consiglio di fare qualcosa come questo:

 //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; } } 

Si noti che in JavaScript, la Guida definitiva 6a edizione, 7.10, si dice che Array.isArray() è implementato usando Object.prototype.toString.call() in ECMAScript 5. Si noti inoltre che se si ha intenzione di preoccuparsi di toString() ‘ Cambiando l’implementazione di s, dovresti anche preoccuparti che anche gli altri metodi incorporati cambino. Perché usare push() ? Qualcuno può cambiarlo! Un simile approccio è sciocco. Il controllo di cui sopra è una soluzione offerta a chi è preoccupato per toString() , ma credo che il controllo non sia necessario.

Quando ho postato questa domanda, la versione di JQuery che stavo usando non includeva una funzione isArray . Se avesse avuto probabilmente l’avrei usato solo fidandosi di quell’implementazione per essere il miglior modo indipendente da browser per eseguire questo particolare controllo di tipo.

Dato che JQuery ora offre questa funzione, lo userei sempre …

 $.isArray(obj); 

(dalla versione 1.6.2) È ancora implementato utilizzando i confronti sulle stringhe nel modulo

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

Ho pensato di aggiungere un’altra opzione per coloro che potrebbero già utilizzare la libreria Underscore.js nel loro script. Underscore.js ha una funzione isArray () (vedi http://underscorejs.org/#isArray ).

 _.isArray(object) 

Restituisce true se object è una matrice.

Se hai a che fare solo con EcmaScript 5 e versioni successive, puoi utilizzare la funzione Array.isArray integrata

per esempio,

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

Se si utilizza Angolare, è ansible utilizzare la funzione 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

Nel JavaScript di Crockford, The Good Parts , esiste una funzione per verificare se l’argomento specificato è un array:

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

Lui spiega:

In primo luogo, chiediamo se il valore è vero. Lo facciamo per rifiutare valori null e altri valori falsy. Secondo, chiediamo se il tipo di valore è ‘object’. Questo sarà vero per oggetti, matrici e (stranamente) null. Terzo, chiediamo se il valore ha una proprietà length che è un numero. Questo sarà sempre vero per gli array, ma di solito non per gli oggetti. In quarto luogo, chiediamo se il valore contiene un metodo di giunzione. Questo sarà di nuovo vero per tutti gli array. Infine, chiediamo se la proprietà length è enumerabile (la lunghezza sarà prodotta da un ciclo for in?). Questo sarà falso per tutti gli array. Questo è il test più affidabile per arrayness che ho trovato. È un peccato che sia così complicato.

Stavo usando questa linea di codice:

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

La soluzione universale è qui sotto:

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

A partire da ECMAScript 5, una soluzione formale è:

 Array.isArray(arr) 

Inoltre, per le vecchie librerie JavaScript, puoi trovare sotto la soluzione anche se non è abbastanza accurata:

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

Le soluzioni sono da http://www.pixelstech.net/topic/85-How-to-check-whether-an-object-is-an-array-or-not-in-JavaScript

codice riferito da 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);}; 

Per coloro che codificano il golf, un test inaffidabile con meno caratteri:

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

Questo è comunemente usato quando si attraversa / si appiattisce una gerarchia:

 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] 

Da w3schools :

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

Mi è piaciuta la risposta di 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; } } 

ma potevi fare semplicemente così:

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

Ho creato questo piccolo codice, che può restituire tipi veri.

Non sono ancora sicuro delle prestazioni, ma è un tentativo di identificare correttamente il tipo di.

https://github.com/valtido/better-typeOf ne ha anche scritto un po ‘qui http://www.jqui.net/jquery/better-typeof-than-the-javascript-native-typeof/

funziona, in modo simile al tipo attuale.

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

Pensa che potrebbe essere necessario un po ‘di messa a punto e tenere conto delle cose, non ho incontrato o testato correttamente. quindi sono stati accolti ulteriori miglioramenti, sia che si tratti di prestazioni saggiate, sia che si tratti di re-porting errato di typeOf.

Penso che usare myObj.constructor == Object e myArray.constructor == Array sia il modo migliore. È quasi 20 volte più veloce rispetto a toString (). Se estendi gli oggetti con i tuoi costruttori e vuoi che quelle creazioni siano considerate “oggetti”, allora questo non funziona, ma per il resto è più veloce. typeof è veloce quanto il metodo del costruttore ma typeof [] == ‘object’ restituisce true che spesso non è desiderabile. http://jsperf.com/constructor-vs-tostring

una cosa da notare è che null.constructor genererà un errore, quindi se si sta verificando la presenza di valori nulli si dovrà prima fare se (testThing! == null) {}

Poiché la proprietà .length è speciale per gli array in javascript, puoi semplicemente dire

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

Underscorejs e molte altre librerie usano questo trucco breve e semplice.

Qualcosa che ho appena trovato:

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