J'ai tableau avec des objets.
Quelque chose comme ça:
var arr = new Array(
{x:1, y:2},
{x:3, y:4}
);
Quand j'essaye:
arr.indexOf({x:1, y:2});
Il retourne -1
.
Si j'ai des chaînes, des nombres ou un autre type d'éléments mais d'objet, alors indexOf()
fonctionne correctement.
Quelqu'un sait-il pourquoi et que dois-je faire pour rechercher des éléments d'objet dans un tableau?
Bien sûr, je parle des manières sauf de faire des clés de hachage de chaîne pour les objets et de les donner à array ...
indexOf compare searchElement aux éléments du tableau en utilisant une égalité stricte (la même méthode est utilisée par l'opérateur ===, ou triple égal à,).
Vous ne pouvez pas utiliser ===
pour vérifier l'équabilité d'un objet.
Comme @RobG a souligné
Notez que par définition, deux objets ne sont jamais égaux, même s'ils ont exactement les mêmes noms et valeurs de propriétés.
objectA === objectB
si et seulement si objectA et objectB font référence au même objet.
Vous pouvez simplement écrire une fonction indexOf personnalisée pour vérifier l'objet.
function myIndexOf(o) {
for (var i = 0; i < arr.length; i++) {
if (arr[i].x == o.x && arr[i].y == o.y) {
return i;
}
}
return -1;
}
Comme indiqué, deux objets ne sont jamais égaux, mais les références peuvent l'être si elles se rapportent au même objet. Pour que le code fasse ce que vous voulez:
var a = {x:1, y:2};
var b = {x:3, y:4};
var arr = [a, b];
alert(arr.indexOf(a)); // 0
Voici une fonction plus générale specialIndexOf . Notez qu'il s'attend à ce que les valeurs des objets soient des primitives, sinon il doit être plus rigoureux.
function specialIndexOf(arr, value) {
var a;
for (var i=0, iLen=arr.length; i<iLen; i++) {
a = arr[i];
if (a === value) return i;
if (typeof a == 'object') {
if (compareObj(arr[i], value)) {
return i;
}
} else {
// deal with other types
}
}
return -1;
// Extremely simple function, expects the values of all
// enumerable properties of both objects to be primitives.
function compareObj(o1, o2, cease) {
var p;
if (typeof o1 == 'object' && typeof o2 == 'object') {
for (p in o1) {
if (o1[p] != o2[p]) return false;
}
if (cease !== true) {
compareObj(o2, o1, true);
}
return true;
}
}
}
var a = new String('fred');
var b = new String('fred');
var arr = [0,1,a];
alert(specialIndexOf(arr, b)); // 2
Cela fonctionne sans code personnalisé
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
Remarque: cela ne donne pas l'index réel, mais seulement si votre objet existe dans la structure de données
Ces objets ne sont pas égaux.
Vous devez implémenter votre propre fonction.
Vous pouvez le faire par exemple:
var index = -1;
arr.forEach(function(v, i) {
if (this.x==v.x && this.y==v.y) index=i;
}, searched);
où searched
est l'un de vos objets (ou non).
(Je le mettrais en œuvre avec une simple boucle mais c'est plus joli avec foreach)
Parce que deux objets distincts ne sont pas ===
l'un pour l'autre, et indexOf
utilise ===
. (Ils ne sont pas non plus ==
l'un à l'autre.)
Exemple:
var a = {x:1, y:2};
var b = {x:1, y:2};
console.log(a === b);
===
et ==
vérifient si leurs opérandes font référence aux objets même objet, et non s'ils se réfèrent à des objets equivalent (objets avec le même prototype et les mêmes propriétés).
Voici une autre solution, où vous passez une fonction de comparaison en tant que paramètre:
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);
}
Vous pouvez ensuite l'utiliser de la manière suivante:
indexOf(arr, {x:1, y:2}, function (a,b) {
return a.x == b.x && a.y == b.y;
});
arr.indexOf({x:1, y:2}, function (a,b) {
return a.x == b.x && a.y == b.y;
});
arr.indexOf({x:1, y:2}, 1, function (a,b) {
return a.x == b.x && a.y == b.y;
});
La bonne chose est que cela appelle toujours l'index d'origine si aucune fonction de comparaison n'est transmise.
[1,2,3,4].indexOf(3);
On dirait que ce type de réponse ne vous intéresse pas, mais c'est le plus simple à faire pour ceux qui sont intéressés
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 + ")"
}
Comme personne n’a mentionné la fonction intégrée Array.prototype.findIndex (), je voudrais mentionner qu’elle répond exactement aux besoins de l’auteur.
La méthode findIndex () renvoie l'index du premier élément du fichier tableau qui satisfait à la fonction de test fournie. Sinon, -1 est revenu.
var array1 = [5, 12, 8, 130, 44];
function findFirstLargeNumber(element) {
return element > 13;
}
console.log(array1.findIndex(findFirstLargeNumber));
// expected output: 3
Dans votre cas ce serait:
arr.findIndex(function(element) {
return element.x == 1 && element.y == 2;
});
Ou en utilisant ES6
arr.findIndex( element => element.x == 1 && element.y == 2 );
Plus d'informations avec l'exemple ci-dessus: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex