Perché Array.indexOf non trova oggetti dall’aspetto identico

Ho una matrice con oggetti.

Qualcosa come questo:

var arr = new Array( {x:1, y:2}, {x:3, y:4} ); 

Quando provo:

 arr.indexOf({x:1, y:2}); 

Restituisce -1 .

Se ho stringhe o numeri o altri tipi di elementi ma object, indexOf() funziona correttamente.

Qualcuno sa perché e cosa dovrei fare per cercare gli elementi dell’object nella matrice?

Certo, intendo i modi tranne fare le stringhe di hash delle stringhe per gli oggetti e dargli un array …

indexOf confronta searchElement con gli elementi dell’array usando l’uguaglianza rigorosa (lo stesso metodo utilizzato dall’operatore ===, o triple-equals,).

Non è ansible utilizzare === per verificare l’equità di un object.

Come ha sottolineato @RobG

Si noti che, per definizione, due oggetti non sono mai uguali, anche se hanno esattamente gli stessi nomi e valori di proprietà. objectA === objectB se e solo se objectA e objectB fanno riferimento allo stesso object.

Puoi semplicemente scrivere una funzione indexOf personalizzata per controllare l’object.

 function myIndexOf(o) { for (var i = 0; i < arr.length; i++) { if (arr[i].x == ox && arr[i].y == oy) { return i; } } return -1; } 

DEMO: http://jsfiddle.net/zQtml/

Come notato, due oggetti non sono mai uguali, ma i riferimenti possono essere uguali se si riferiscono allo stesso object, quindi per fare in modo che il codice faccia ciò che vuoi:

 var a = {x:1, y:2}; var b = {x:3, y:4}; var arr = [a, b]; alert(arr.indexOf(a)); // 0 

modificare

Ecco una funzione specialeIndexOf più generale. Si noti che si aspetta che i valori degli oggetti siano primitivi, altrimenti deve essere più rigoroso.

 function specialIndexOf(arr, value) { var a; for (var i=0, iLen=arr.length; i 

Funziona senza codice personalizzato

 var arr, a, found; arr = [{x: 1, y: 2}]; a = {x: 1, y: 2}; found = JSON.stringify(arr).indexOf(JSON.stringify(a)) > - 1; // found === true 

Nota: questo non fornisce l’indice attuale, ma indica solo se l’object esiste nella struttura dati corrente

Quegli oggetti non sono uguali.

È necessario implementare la propria funzione.

Puoi farlo ad esempio:

 var index = -1; arr.forEach(function(v, i) { if (this.x==vx && this.y==vy) index=i; }, searched); 

dove searched è uno dei tuoi oggetti (o meno).

(Lo implementerei con un ciclo semplice ma è più carino con foreach)

Poiché due oggetti separati non sono === l’uno con l’altro e indexOf utilizza === . (Non sono neanche == l’un l’altro).

Esempio:

 var a = {x:1, y:2}; var b = {x:1, y:2}; console.log(a === b); 

Ecco un’altra soluzione, in cui si passa una funzione di confronto come parametro:

 function indexOf(array, val, from, compare) { if (!compare) { if (from instanceof Function) { compare = from; from = 0; } else return array.__origIndexOf(val, from); } if (!from) from = 0; for (var i=from ; i < array.length ; i++) { if (compare(array[i], val)) return i; } return -1; } // Save original indexOf to keep the original behaviour Array.prototype.__origIndexOf = Array.prototype.indexOf; // Redefine the Array.indexOf to support a compare function. Array.prototype.indexOf = function(val, from, compare) { return indexOf(this, val, from, compare); } 

Puoi quindi usarlo in questo modo:

 indexOf(arr, {x:1, y:2}, function (a,b) { return ax == bx && ay == by; }); arr.indexOf({x:1, y:2}, function (a,b) { return ax == bx && ay == by; }); arr.indexOf({x:1, y:2}, 1, function (a,b) { return ax == bx && ay == by; }); 

La cosa buona è che questo chiama ancora l'indice originaleOf se non viene passata alcuna funzione di confronto.

 [1,2,3,4].indexOf(3); 

Sembra che tu non sia interessato a questo tipo di risposta, ma è il più semplice da fare per gli altri che sono interessati:

 var arr = new Array( {x:1, y:2}, {x:3, y:4} ); arr.map(function(obj) { return objStr(obj); }).indexOf(objStr({x:1, y:2})); function objStr(obj) { return "(" + obj.x + ", " + obj.y + ")" } 

Dato che nessuno ha menzionato la funzione built-in Array.prototype.findIndex (), vorrei dire che fa esattamente ciò di cui l’autore ha bisogno.

Il metodo findIndex () restituisce l’indice del primo elemento dell’array che soddisfa la funzione di test fornita. Altrimenti viene restituito -1.

 var array1 = [5, 12, 8, 130, 44]; function findFirstLargeNumber(element) { return element > 13; } console.log(array1.findIndex(findFirstLargeNumber)); // expected output: 3 

Nel tuo caso sarebbe:

 arr.findIndex(function(element) { return element.x == 1 && element.y == 2; }); 

O usando ES6

 arr.findIndex( element => element.x == 1 && element.y == 2 ); 

Maggiori informazioni con l’esempio sopra: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex