2013-05-24 14 views
7

Identificare quali oggetti sono is complicated in JavaScript e determinare quali oggetti sono matrici ha qualcosa di hacky solution. Per fortuna, riesce a lavorare in entrambi i seguenti casi:È possibile determinare se un oggetto creato con Object.create eredita dalla matrice in JavaScript?

Object.prototype.toString.call([]);   // [object Array] 
Object.prototype.toString.call(new Array()); // [object Array] 

Grande, non [object Object] in vista! Purtroppo, questo metodo riesce ancora a fallire con questo:

var arr = Object.create(Array.prototype); 
Object.prototype.toString.call(arr);   // [object Object] 

Questo è frustrante, per non dire altro. Il mio oggetto arr ha tutti i metodi di un array, funziona come un array e, per tutti gli scopi, lo è un array. Tuttavia JavaScript non fornisce gli strumenti per identificarlo come tale.

C'è un modo per capire se un oggetto eredita da un particolare prototipo? Suppongo che si possa scorrere i prototipi in questo modo:

function inherits(obj, proto) { 
    while (obj != null) { 
     if (obj == proto) return true; 
     obj = Object.getPrototypeOf(obj); 
    } 
    return false; 
} 

inherits(Object.create(Array.prototype), Array.prototype); // true 

Ma ci si sente un po 'hacky. C'è un approccio più pulito?

+0

Sono solo curioso: perché mai creare un array come questo? 'Object.create (Array.prototyp);' e lo controlla tramite 'Object.prototype.toString.call (arr);' – Zim84

+0

@ Zim84: Penso che questo sia solo un esempio. Nelle applicazioni reali, non dovremmo mai farlo. Nelle applicazioni reali, Object.create (Array.prototype) può essere chiamato da qualche altra parte e passare l'oggetto creato a un'altra funzione –

+0

Il problema è che in realtà non si dispone di un array vero (ad esempio non ha il magico ' proprietà di lunghezza', solo una che sembra a prima vista). Quello che hai è un array che sembra avere tutti i metodi di un vero array. Se vuoi verificare la presenza di array-like, dovresti semplicemente vedere se ha una proprietà 'length' e non è una stringa. Questo è il migliore IMO. Se si desidera verificare la presenza di allineamenti veri, continuare a utilizzare 'Object.prototype.toString.call' o' Array.isArray' e sapere che un oggetto con prototipo di 'Array.prototype' non è necessariamente un array vero. –

risposta

2

Come su un operatore instanceof? Esso restituisce true per tutti i vostri casi:

[] instanceof Array //true 
new Array() instanceof Array //true 
Object.create(Array.prototype) instanceof Array //true 

Tuttavia:

Object.create(Array.prototype) instanceof Object //also true 

quindi state attenti.

+0

instanceof Array non fornisce un metodo affidabile per verificare quando si passano gli array avanti e indietro tra i frame poiché ogni frame ha il proprio costruttore di array –

+0

Questa è una soluzione ragionevole per gli ambienti a frame singolo o il nodo. Basta tenere a mente il problema del multi-frame. –

2

ECMAScript 5 ha introdotto Array.isArray() in javascript che fornisce un modo affidabile per controllare. Per i vecchi browser, fissiamo che, (citato da questa book)

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

Ma ho appena scoperto la funzione built-in Array.isArray non funziona correttamente quando usiamo Object.create (testato in cromo). Mi si avvicinò con un metodo che funziona:

function isArray(value) { 
    if (typeof value === "undefined" || value === null) { 
      return false; 
    } 
    do { 
      if (Object.prototype.toString.call(value) === "[object Array]") { 
       return true; 
      } 
      value= Object.getPrototypeOf(value); 
    } while (value); 

    return false; 
} 

usarlo:

var arr = Object.create(Array.prototype); 
var arr1 = Object.create(Object.create(Array.prototype)); 
var arr2 = new Array(); 
var arr3 = []; 
isArray(arr); 
isArray(arr1); 
isArray(arr2); 
isArray(arr3); 
+1

'Array.isArray' è esattamente lo stesso di' Object.prototype.toString.call (arr) == '[oggetto Array]' '. Questa soluzione non funzionerà se il prototipo dell'oggetto è un oggetto che ha un prototipo che è una matrice. 'var arr = Object.create (Object.create (Array.prototype));' –

+0

@NathanWall: dai un'occhiata a questo [libro] (http://books.google.com.vn/books?id=J5RCV8yM7sEC&pg= PA88 & LPG = PA88 & dq = mantenibile + javascript + rilevazione + matrice & source = bl & OTS = TDZEDzhWJm & sig = I92iJt7mAz8rEdHteDFAmCSqLzI & hl = vi & sa = X & ei = XHShUZnkLY6diAerxICgCg & ved = 0CDEQ6AEwAQ # v = onepage & q = mantenibile% 20javascript% 20detecting% 20array & f = false) –

+0

@NathanWall: controllare la risposta aggiornata. Grazie. –

0

Come circa il controllo del costruttore?

function inherits(obj, proto) { 
    return obj.constructor === proto.constructor; 
} 

inherits(Object.create(Array.prototype), Array.prototype); // true 
2

Vedere http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/ per l'esposizione definitiva dei problemi in eredita dalla matrice.

Ad ogni modo, nel caso più semplice, in cui si sta facendo

var sort_of_an_array = Object.create(Array.prototype); 

si può controllare usando isPrototypeOf:

Array.prototype.isPrototypeOf(sort_of_an_array) 

Vedi https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/isPrototypeOf.

0

funziona come una matrice, e in ogni caso, è un array

No. Non ha length struttura auto-aggiornamento. Vedi this article perché è quasi impossibile creare una sottoclasse di Array.

C'è un modo per capire se un oggetto eredita da un particolare prototipo? Suppongo che tu possa scorrere i prototipi, ma sembra un po 'hacky.

Questo è solo come farlo. Un approccio più pulito di una funzione di auto-scritta sarebbe quella di utilizzare il instanceof operator:

arr instanceof Array; // true 
Problemi correlati