Un opérateur d'égalité stricte vous dira si deux types d' objet sont égaux. Cependant, existe-t-il un moyen de savoir si deux objets sont égaux, un peu comme la valeur du code de hachage en Java?
Question de dépassement de pile Existe-t-il une sorte de fonction hashCode en JavaScript? est similaire à cette question, mais nécessite une réponse plus académique. Le scénario ci-dessus montre pourquoi il serait nécessaire d'en avoir un, et je me demande s'il existe une solution équivalente .
javascript
object
equals
hashcode
Communauté
la source
la source
a.hashCode() == b.hashCode()
n'implique pas que cea
soit égal àb
. C'est une condition nécessaire, pas suffisante.Réponses:
La réponse courte
La réponse est simple: non, il n'y a pas de moyen générique pour déterminer qu'un objet est égal à un autre dans le sens que vous entendez. L'exception est lorsque vous pensez strictement à un objet sans type.
La réponse longue
Le concept est celui d'une méthode Equals qui compare deux instances différentes d'un objet pour indiquer si elles sont égales à un niveau de valeur. Cependant, c'est au type spécifique de définir comment une
Equals
méthode doit être implémentée. Une comparaison itérative d'attributs qui ont des valeurs primitives peut ne pas être suffisante, il peut bien y avoir des attributs qui ne doivent pas être considérés comme faisant partie de la valeur de l'objet. Par exemple,Dans ce cas ci-dessus, il
c
n'est pas vraiment important de déterminer si deux instances de MyClass sont égales, uniquementa
etb
sont importantes. Dans certains cas, celac
peut varier d'une instance à l'autre et ne pas être significatif lors de la comparaison.Notez que ce problème s'applique lorsque les membres peuvent eux-mêmes être des instances d'un type et que chacun d'eux devrait tous avoir un moyen de déterminer l'égalité.
Pour compliquer encore les choses, en JavaScript, la distinction entre données et méthode est floue.
Un objet peut référencer une méthode qui doit être appelée en tant que gestionnaire d'événements, et cela ne serait probablement pas considéré comme faisant partie de son «état de valeur». Alors qu'un autre objet peut très bien se voir attribuer une fonction qui effectue un calcul important et rend ainsi cette instance différente des autres simplement parce qu'elle fait référence à une fonction différente.
Qu'en est-il d'un objet dont l'une de ses méthodes de prototype existantes est remplacée par une autre fonction? Pourrait-elle encore être considérée comme égale à une autre instance qu'elle serait par ailleurs identique? Cette question ne peut être répondue que dans chaque cas spécifique pour chaque type.
Comme indiqué précédemment, l'exception serait un objet strictement sans type. Dans ce cas, le seul choix judicieux est une comparaison itérative et récursive de chaque membre. Même alors, il faut se demander quelle est la «valeur» d'une fonction?
la source
_.isEqual(obj1, obj2);
.equals
méthode n'est pas anodin, c'est pourquoi il y a un tel sujet dédié dans Java efficace .javascript equality object
, obtenu tl; dr réponse, a pris une ligne du commentaire @chovy. merciangular.equals
Pourquoi réinventer la roue? Essayez Lodash . Il a un certain nombre de fonctions indispensables telles que isEqual () .
Il vérifiera brutalement chaque valeur de clé - tout comme les autres exemples de cette page - en utilisant ECMAScript 5 et des optimisations natives si elles sont disponibles dans le navigateur.
Remarque: Auparavant, cette réponse recommandait Underscore.js , mais lodash a fait un meilleur travail pour corriger les bogues et résoudre les problèmes avec cohérence.
la source
L'opérateur d'égalité par défaut dans JavaScript pour les objets donne la valeur true lorsqu'ils se réfèrent au même emplacement en mémoire.
Si vous avez besoin d'un opérateur d'égalité différent, vous devrez ajouter une
equals(other)
méthode, ou quelque chose comme ça à vos classes et les spécificités de votre domaine problématique détermineront ce que cela signifie exactement.Voici un exemple de carte à jouer:
la source
{x:1, y:2}
! =={y:2, x:1}
Si vous travaillez dans AngularJS , la
angular.equals
fonction déterminera si deux objets sont égaux. Dans Ember.js, utilisezisEqual
.angular.equals
- Voir les documents ou la source pour en savoir plus sur cette méthode. Il effectue également une comparaison approfondie sur les tableaux.isEqual
- Voir la documentation ou la source pour en savoir plus sur cette méthode. Il ne fait pas de comparaison approfondie sur les tableaux.la source
Ceci est ma version. Il utilise la nouvelle fonctionnalité Object.keys introduite dans ES5 et les idées / tests de + , + et + :
la source
objectEquals([1,2,undefined],[1,2])
retourstrue
objectEquals([1,2,3],{0:1,1:2,2:3})
renvoie égalementtrue
- par exemple, il n'y a pas de vérification de type, uniquement une vérification de clé / valeur.objectEquals(new Date(1234),1234)
retournetrue
Si vous utilisez une bibliothèque JSON, vous pouvez coder chaque objet en JSON, puis comparer l'égalité des chaînes résultantes.
REMARQUE: Bien que cette réponse fonctionne dans de nombreux cas, comme plusieurs personnes l'ont souligné dans les commentaires, elle est problématique pour diverses raisons. Dans presque tous les cas, vous souhaiterez trouver une solution plus robuste.
la source
Implémentation fonctionnelle courte
deepEqual
:Edit : version 2, en utilisant la suggestion de jib et les fonctions flèches ES6:
la source
reduce
parevery
pour simplifier.Object.keys(x).every(key => deepEqual(x[key], y[key]))
.: (x === y)
par: (x === y && (x != null && y != null || x.constructor === y.constructor))
Essayez-vous de tester si deux objets sont égaux? c'est à dire: leurs propriétés sont égales?
Si tel est le cas, vous aurez probablement remarqué cette situation:
vous devrez peut-être faire quelque chose comme ceci:
Évidemment, cette fonction pourrait faire un peu d'optimisation et la possibilité de faire une vérification approfondie (pour gérer les objets imbriqués:
var a = { foo : { fu : "bar" } }
mais vous avez l'idée.Comme FOR l'a souligné, vous devrez peut-être l'adapter à vos propres besoins, par exemple: différentes classes peuvent avoir différentes définitions de «égal». Si vous travaillez uniquement avec des objets simples, ce qui précède peut suffire, sinon une
MyClass.equals()
fonction personnalisée peut être la solution.la source
Si vous avez une fonction de copie approfondie à portée de main, vous pouvez utiliser l'astuce suivante pour continuer à utiliser
JSON.stringify
tout en respectant l'ordre des propriétés:Démo: http://jsfiddle.net/CU3vb/3/
Raisonnement:
Étant donné que les propriétés de
obj1
sont copiées dans le clone une par une, leur ordre dans le clone sera conservé. Et lorsque les propriétés deobj2
sont copiées dans le clone, puisque les propriétés déjà existantes dansobj1
seront simplement écrasées, leurs ordres dans le clone seront préservés.la source
Dans Node.js, vous pouvez utiliser son native
require("assert").deepStrictEqual
. Plus d'informations: http://nodejs.org/api/assert.htmlPar exemple:
Un autre exemple qui renvoie
true
/false
au lieu de renvoyer des erreurs:la source
Chai
a cette fonctionnalité aussi. Dans son cas, vous utiliserez:var foo = { a: 1 }; var bar = { a: 1 }; expect(foo).to.deep.equal(bar); // true;
error.name
sur"AssertionError [ERR_ASSERTION]"
. Dans ce cas, je remplacerais l'instruction if parif (error.code === 'ERR_ASSERTION') {
.deepStrictEqual
la voie à suivre. J'avais fait trembler mon cerveau en essayant de comprendre pourquoistrictEqual
ne fonctionnait pas. Fantastique.Solutions les plus simples et logiques pour comparer tout comme Object, Array, String, Int ...
JSON.stringify({a: val1}) === JSON.stringify({a: val2})
Remarque:
val1
etval2
avec votre objetla source
JSON.stringify
qu'une réorganisation alphabétique? (Ce que je ne trouve pas documenté .)J'utilise cette
comparable
fonction pour produire des copies de mes objets qui sont comparables au JSON:Pratique dans les tests (la plupart des frameworks de test ont une
is
fonction). Par exempleSi une différence est détectée, les chaînes sont enregistrées, ce qui rend les différences visibles:
la source
Heres est une solution dans ES6 / ES2015 utilisant une approche de style fonctionnel:
démo disponible ici
la source
Je ne sais pas si quelqu'un a posté quelque chose de similaire, mais voici une fonction que j'ai créée pour vérifier les égalités d'objets.
En outre, il est récursif, il peut donc également vérifier une profonde égalité, si c'est ce que vous appelez.
la source
Pour ceux d'entre vous qui utilisent NodeJS, il existe une méthode pratique appelée
isDeepStrictEqual
sur la bibliothèque native Util qui peut y parvenir.https://nodejs.org/api/util.html#util_util_isdeepstrictequal_val1_val2
la source
ES6: Voici le code minimum que je pourrais faire. Il effectue une comparaison approfondie récursivement en stringifiant tous les objets, la seule limitation est qu'aucune méthode ou aucun symbole n'est comparé.
la source
vous pouvez utiliser
_.isEqual(obj1, obj2)
partir de la bibliothèque underscore.js.Voici un exemple:
Voir la documentation officielle ici: http://underscorejs.org/#isEqual
la source
En supposant que l'ordre des propriétés dans l'objet n'est pas modifié.
JSON.stringify () fonctionne pour les deux types d'objets profonds et non profonds, pas très sûr des aspects de performance:
la source
Une solution simple à ce problème que beaucoup de gens ne réalisent pas est de trier les chaînes JSON (par caractère). C'est aussi généralement plus rapide que les autres solutions mentionnées ici:
Une autre chose utile à propos de cette méthode est que vous pouvez filtrer les comparaisons en passant une fonction "replacer" aux fonctions JSON.stringify ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON / stringify # Example_of_using_replacer_parameter ). Les éléments suivants comparent uniquement toutes les clés d'objets nommées "derp":
la source
areEqual({a: 'b'}, {b: 'a'})
obtienttrue
alors?Je voulais juste contribuer ma version de comparaison d'objets en utilisant certaines fonctionnalités d'es6. Il ne tient pas compte d'une commande. Après avoir converti tous les if / else en ternaire, je suis venu avec ce qui suit:
la source
Ayant besoin d'une fonction de comparaison d'objets plus générique que celle publiée, j'ai concocté ce qui suit. Critique appréciée ...
la source
Object.prototype
lorsque vous modifiez - dans la grande majorité des cas, il n'est pas conseillé (des ajouts apparaissent dans toutes les boucles for..in, par exemple). Peut-être envisagerObject.equals = function(aObj, bObj) {...}
?Si vous comparez des objets JSON, vous pouvez utiliser https://github.com/mirek/node-rus-diff
Usage:
Si deux objets sont différents, un
{$rename:{...}, $unset:{...}, $set:{...}}
objet similaire compatible MongoDB est renvoyé.la source
J'ai fait face au même problème et j'ai décidé d'écrire ma propre solution. Mais parce que je veux également comparer des tableaux avec des objets et vice-versa, j'ai conçu une solution générique. J'ai décidé d'ajouter les fonctions au prototype, mais on peut facilement les réécrire en fonctions autonomes. Voici le code:
Cet algorithme est divisé en deux parties; La fonction equals elle-même et une fonction pour trouver l'index numérique d'une propriété dans un tableau / objet. La fonction find est uniquement nécessaire car indexof ne trouve que des nombres et des chaînes et aucun objet.
On peut l'appeler ainsi:
La fonction retourne vrai ou faux, dans ce cas vrai. L'algorithme permet également de comparer des objets très complexes:
L'exemple supérieur retournera vrai, même si les propriétés ont un ordre différent. Un petit détail à surveiller: Ce code vérifie également le même type de deux variables, donc "3" n'est pas le même que 3.
la source
Je vois des réponses de code de spaghetti. Sans utiliser de bibliothèques tierces, c'est très simple.
Triez d'abord les deux objets en saisissant leurs noms de clé.
Ensuite, utilisez simplement une chaîne pour les comparer.
la source
Je déconseille le hachage ou la sérialisation (comme le suggère la solution JSON). Si vous devez tester si deux objets sont égaux, vous devez définir ce que signifie égal. Il se peut que tous les membres de données des deux objets correspondent, ou que les emplacements de mémoire doivent correspondre (ce qui signifie que les deux variables référencent le même objet en mémoire), ou que seul un membre de données de chaque objet doit correspondre.
Récemment, j'ai développé un objet dont le constructeur crée un nouvel identifiant (à partir de 1 et incrémentant de 1) chaque fois qu'une instance est créée. Cet objet a une fonction isEqual qui compare cette valeur id avec la valeur id d'un autre objet et renvoie true si elles correspondent.
Dans ce cas, j'ai défini "égal" comme signifiant la correspondance des valeurs id. Étant donné que chaque instance a un identifiant unique, cela pourrait être utilisé pour renforcer l'idée que les objets correspondants occupent également le même emplacement de mémoire. Bien que ce ne soit pas nécessaire.
la source
Il est utile de considérer deux objets égaux s'ils ont toutes les mêmes valeurs pour toutes les propriétés et récursivement pour tous les objets et tableaux imbriqués. Je considère également les deux objets suivants égaux:
De même, les tableaux peuvent avoir des éléments "manquants" et des éléments non définis. Je les traiterais également de la même manière:
Une fonction qui met en œuvre cette définition de l'égalité:
Code source (y compris les fonctions d'assistance, generalType et uniqueArray): Unit Test et Test Runner ici .
la source
Je fais les hypothèses suivantes avec cette fonction:
Cela devrait être considéré comme la démonstration d'une stratégie simple.
la source
C'est un ajout pour tout ce qui précède, pas un remplacement. Si vous devez comparer rapidement des objets peu profonds sans avoir besoin de vérifier les cas récursifs supplémentaires. Voici une photo.
Cela se compare à: 1) égalité du nombre de propriétés propres, 2) égalité des noms de clé, 3) si bCompareValues == true, égalité des valeurs de propriété correspondantes et de leurs types (triple égalité)
la source
Pour comparer des clés pour des instances d'objets de paires clé / valeur simples, j'utilise:
Une fois les clés comparées, un simple supplément
for..in
boucle suffit.La complexité est O (N * N) avec N est le nombre de clés.
J'espère / devine que les objets que je définis ne contiendront pas plus de 1000 propriétés ...
la source
Je sais que c'est un peu vieux, mais je voudrais ajouter une solution que j'ai trouvée pour ce problème. J'avais un objet et je voulais savoir quand ses données changeaient. "quelque chose de similaire à Object.observe" et ce que j'ai fait était:
Ceci peut être dupliqué ici et créer un autre ensemble de tableaux pour comparer les valeurs et les clés. C'est très simple car ce sont maintenant des tableaux et retourneront faux si les objets ont des tailles différentes.
la source
false
, car les tableaux ne se comparent pas par valeur, par exemple[1,2] != [1,2]
.