2012-09-27 19 views
13

Mi stavo confondendo un po 'con un esperimento mentale e ora sto cercando qualche consiglio. Si tratta di riferimenti ECMAscript e del metodo Array.prototype.indexOf().Come risolve i riferimenti indexOf() di Javascript

Iniziamo facile:

var container = [ ]; 
// more code 
container.push(5); 
container.push(7); 
container.push(10); 

Così ora abbiamo spinto alcuni "valori primitivi" nella nostra gamma ECMAscript (anche questa affermazione è vera Tornerò per), a Almeno l'ho immaginato così fino ad ora. Una chiamata a

container.indexOf(7); 

tornerà 1 come previsto. La grande domanda che ho è, se .indexOf() confronta davvero il valore primitivo o se in realtà un oggetto Number() viene creato + memorizzato e il suo riferimento viene confrontato. Questo diventa un po 'più evidente se si ri-scrittura che in questo modo:

var a = 5, 
    b = 7, 
    c = 10; 

var container = [ ]; 

container.push(a); 
container.push(b); 
container.push(c); 

container.indexOf(b); 

Fino a questo punto, si potrebbe ancora facilmente obiettare che tutti i .indexOf() deve fare è quello di confrontare i valori, ma ora consente di guardare qualcosa di simile:

var a = { name: 'a', value: 5 }, 
    b = { name: 'b', value: 10 }, 
    c = { name: 'c', value: 15 }; 

var container = [ ]; 
// more code 
container.push(a); 
container.push(b); 
container.push(c); 

Qui, abbiamo riempito tale matrice contenitore con oggettuali riferimenti ed ancora, .indexOf() opere come previsto

container.indexOf(b) // === 1 

durante una chiamata del genere

container.indexOf({ name: 'b', value: 10 }); 

ritorna ovviamente -1 poiché stiamo creando un nuovo oggetto e ottenere un nuovo riferimento. Quindi qui deve confrontare internamente i riferimenti tra loro, giusto?

Qualche genio delle specifiche ECMAscript può confermarmi o, meglio ancora, collegarmi un po 'di materiale a riguardo?

Una domanda laterale su questo sarebbe se non v'è alcun modo possibilmente per accedere a un oggetto riferimento memorizzato internamente di un lexicalEnvironment rispettivamente attivazione oggetto.

+0

Se funziona ovunque simile ad altre lingue, quindi 'indexOf' funziona su hash di oggetti in cui gli oggetti di solito hanno valori diversi e oggetti primitivi di solito hanno un hash costante basata su il loro valore (per interi, questo è molto spesso solo il valore intero stesso). Quindi due oggetti int "5" e "5" hanno entrambi l'hash "5" e in quanto tali sono "uguali". – poke

+1

Ho iniziato a scrivere una risposta, ma poi si è trasformato in un post sul blog, così mi sono fermato e mi sono scoraggiato dal riscriverlo. Ma se sei interessato: http://pastie.org/4828933 – Zirak

risposta

8

Si riduce a indexOf() confrontando a turno ciascuna proprietà di matrice utilizzando lo stesso algoritmo dell'operatore ===.

La sezione pertinente delle specifiche ECMAScript 5 è la sezione 15.4.4.14, passaggio 9, sezione b (evidenziazione mia):

Se kPresent è vero, allora

i. Lascia che l'elemento K sia il risultato della chiamata al metodo interno [[Ottieni]] di O con l'argomento ToString (k).

ii. Sia lo stesso risultato dell'applicazione dell'elgoritmo di confronto rigoroso di uguaglianza per searchElement e elementK.

iii. Se lo stesso è vero, restituisci k.

Riferimenti:

+0

bel colpo di testa grazie. Tuttavia, il * confronto di uguaglianza rigorosa * descritto non descrive come trattare gli oggetti in generale? Sembra che descrivano solo numeri, stringhe, booleani e valori null/non definiti. Inoltre, sono curioso anche della prima sezione che dice "* chiamando toString() *" sull'argomento. Se questo è realmente il 'toString nativo allora tutti gli oggetti dovrebbero restituire * oggetto Oggetto * no? – jAndy

+0

@jAndy: il bit 'ToString (k)' si riferisce al nome della proprietà, non al valore. La rigorosa sezione di confronto sull'uguaglianza descrive completamente l'algoritmo. Vedere il punto 7 in 11.9.6: * "Restituisce true se xey si riferiscono allo stesso oggetto, altrimenti restituisce false." *. –

2

Non sono sicuro se questo è garantito su tutte le implementazioni ECMAScript o no, ma lo Mozilla documentation afferma che usa l'uguaglianza rigorosa per effettuare il confronto (===). In quanto tale, ciò mostrerebbe il comportamento che descrivete, confrontandolo per valori su primitive, ma per riferimento sugli oggetti (vedere strict equality).

+0

Anche '==' usa il confronto per riferimento per gli oggetti. Quindi non ha nulla a che fare con l'uguaglianza rigorosa – zerkms

+3

Non sto dicendo che sia * a causa di * rigorosa uguaglianza. Sto dicendo che in realtà sta usando l'uguaglianza rigorosa e questo è coerente con il comportamento che descrive. – Thor84no

0

@ Tim Down è giusto. indexOf esegue un confronto rigoroso. Sto dando una dimostrazione di questo eseguendo l'override valueOf funzione

var MyObject = function(n, v){ 
    this.name = n; 
    this.value = v; 
} 

MyObject.prototype.valueOf = function(){ 
    return this.value; 
} 

var a = new MyObject("a", 5); 
var b = new MyObject("b", 10); 
var c = new MyObject("c", 15); 

var container = [ ]; 

container.push(a); 
container.push(b); 
container.push(c); 

console.log(b == 10); // true 
console.log(container[1] == 10); // true 

console.log(b === 10); // false 
container.indexOf(10); // -1 
Problemi correlati