Ein strikter Gleichheits - Operator werden Ihnen sagen , wenn zwei Objekttypen gleich sind. Gibt es jedoch eine Möglichkeit, festzustellen, ob zwei Objekte gleich sind, ähnlich wie beim Hash-Code Wert in Java?
Frage zum Stapelüberlauf Gibt es eine HashCode-Funktion in JavaScript? ähnelt dieser Frage, erfordert jedoch eine akademischere Antwort. Das obige Szenario zeigt, warum es notwendig wäre, eine zu haben, und ich frage mich, ob es eine gleichwertige Lösung gibt .
javascript
object
equals
hashcode
Gemeinschaft
quelle
quelle
a.hashCode() == b.hashCode()
ist nicht bedeuten , dassa
gleichb
. Es ist eine notwendige Bedingung, keine ausreichende.Antworten:
Die kurze Antwort
Die einfache Antwort lautet: Nein, es gibt keine generischen Mittel, um festzustellen, ob ein Objekt einem anderen in dem von Ihnen gemeinten Sinne gleich ist. Die Ausnahme ist, wenn Sie streng daran denken, dass ein Objekt typenlos ist.
Die lange Antwort
Das Konzept ist das einer Equals-Methode, bei der zwei verschiedene Instanzen eines Objekts verglichen werden, um anzuzeigen, ob sie auf einer Wertebene gleich sind. Es ist jedoch Sache des jeweiligen Typs, zu definieren, wie eine
Equals
Methode implementiert werden soll. Ein iterativer Vergleich von Attributen mit primitiven Werten reicht möglicherweise nicht aus. Es kann durchaus Attribute geben, die nicht als Teil des Objektwerts betrachtet werden sollen. Zum Beispiel,In diesem obigen Fall
c
ist es nicht wirklich wichtig zu bestimmen, ob zwei Instanzen von MyClass gleich sind, nura
undb
sind wichtig. In manchen Fällenc
kann dies zwischen den Instanzen variieren und ist beim Vergleich dennoch nicht signifikant.Beachten Sie, dass dieses Problem auftritt, wenn Mitglieder selbst auch Instanzen eines Typs sein können und diese alle über ein Mittel zur Bestimmung der Gleichheit verfügen müssen.
Erschwerend kommt hinzu, dass in JavaScript die Unterscheidung zwischen Daten und Methode unscharf ist.
Ein Objekt kann auf eine Methode verweisen, die als Ereignishandler aufgerufen werden soll, und dies wird wahrscheinlich nicht als Teil seines 'Wertezustands' betrachtet. Während einem anderen Objekt durchaus eine Funktion zugewiesen werden kann, die eine wichtige Berechnung durchführt und dadurch diese Instanz von anderen unterscheidet, nur weil sie auf eine andere Funktion verweist.
Was ist mit einem Objekt, bei dem eine der vorhandenen Prototypmethoden von einer anderen Funktion überschrieben wird? Könnte es immer noch als gleichwertig mit einer anderen Instanz angesehen werden, dass es ansonsten identisch ist? Diese Frage kann nur in jedem Einzelfall für jeden Typ beantwortet werden.
Wie bereits erwähnt, wäre die Ausnahme ein streng typenloses Objekt. In diesem Fall ist die einzig sinnvolle Wahl ein iterativer und rekursiver Vergleich jedes Mitglieds. Selbst dann muss man sich fragen, was der 'Wert' einer Funktion ist.
quelle
_.isEqual(obj1, obj2);
.equals
Methode ist nicht trivial, weshalb es in Effective Java ein solches Thema gibt .javascript equality object
, bekam tl; dr Antwort, nahm Einzeiler von @chovy Kommentar. Vielen Dankangular.equals
Warum das Rad neu erfinden? Probieren Sie Lodash aus . Es hat eine Reihe von Must-Have-Funktionen wie isEqual () .
Jeder Schlüsselwert wird - genau wie in den anderen Beispielen auf dieser Seite - mithilfe von ECMAScript 5 und nativen Optimierungen brutal überprüft, sofern diese im Browser verfügbar sind.
Hinweis: Früher empfahl diese Antwort Underscore.js , aber lodash hat es besser gemacht, Fehler zu beheben und Probleme mit Konsistenz zu beheben.
quelle
Der Standard-Gleichheitsoperator in JavaScript für Objekte ergibt true, wenn sie sich auf denselben Speicherort im Speicher beziehen.
Wenn Sie einen anderen Gleichheitsoperator benötigen, müssen
equals(other)
Sie Ihren Klassen eine Methode oder ähnliches hinzufügen , und die Besonderheiten Ihrer Problemdomäne bestimmen, was genau dies bedeutet.Hier ist ein Spielkartenbeispiel:
quelle
{x:1, y:2}
! =={y:2, x:1}
Wenn Sie in AngularJS arbeiten , ermittelt die
angular.equals
Funktion, ob zwei Objekte gleich sind. In Ember.js verwendenisEqual
.angular.equals
- Weitere Informationen zu dieser Methode finden Sie in den Dokumenten oder in der Quelle . Es macht auch einen tiefen Vergleich bei Arrays.isEqual
- Weitere Informationen zu dieser Methode finden Sie in den Dokumenten oder in der Quelle . Es wird kein tiefer Vergleich für Arrays durchgeführt.quelle
Das ist meine Version. Es verwendet die neue Funktion Object.keys , die in ES5 eingeführt wird, sowie Ideen / Tests von + , + und + :
quelle
objectEquals([1,2,undefined],[1,2])
Rückkehrtrue
objectEquals([1,2,3],{0:1,1:2,2:3})
gibt auch zurücktrue
- zB gibt es keine Typprüfung, nur Schlüssel- / Wertprüfung.objectEquals(new Date(1234),1234)
kehrt zurücktrue
Wenn Sie eine JSON-Bibliothek verwenden, können Sie jedes Objekt als JSON codieren und dann die resultierenden Zeichenfolgen auf Gleichheit vergleichen.
HINWEIS: Obwohl diese Antwort in vielen Fällen funktioniert, ist sie aus verschiedenen Gründen problematisch, wie mehrere Personen in den Kommentaren hervorgehoben haben. In fast allen Fällen möchten Sie eine robustere Lösung finden.
quelle
Kurze funktionale
deepEqual
Implementierung:Bearbeiten : Version 2 mit Jibs Vorschlag und ES6-Pfeilfunktionen:
quelle
reduce
mitevery
zu vereinfachen.Object.keys(x).every(key => deepEqual(x[key], y[key]))
.: (x === y)
mit: (x === y && (x != null && y != null || x.constructor === y.constructor))
Versuchen Sie zu testen, ob zwei Objekte gleich sind? dh: ihre Eigenschaften sind gleich?
Wenn dies der Fall ist, haben Sie wahrscheinlich diese Situation bemerkt:
Möglicherweise müssen Sie Folgendes tun:
Offensichtlich könnte diese Funktion einiges an Optimierung und die Möglichkeit einer gründlichen Überprüfung (zur Behandlung verschachtelter Objekte) vertragen:
var a = { foo : { fu : "bar" } }
aber Sie haben die Idee.Wie FOR hervorhob, müssen Sie dies möglicherweise für Ihre eigenen Zwecke anpassen, z. B.: Verschiedene Klassen haben möglicherweise unterschiedliche Definitionen von "gleich". Wenn Sie nur mit einfachen Objekten arbeiten, kann das oben Genannte ausreichen, andernfalls kann eine benutzerdefinierte
MyClass.equals()
Funktion der richtige Weg sein.quelle
Wenn Sie eine tiefe Kopierfunktion zur Hand haben, können Sie den folgenden Trick verwenden , um noch verwendet werden,
JSON.stringify
während die Reihenfolge der Objekte in dieser Auswahl:Demo: http://jsfiddle.net/CU3vb/3/
Begründung:
Da die Eigenschaften von
obj1
einzeln in den Klon kopiert werden, bleibt ihre Reihenfolge im Klon erhalten. Und wenn die Eigenschaften vonobj2
in den Klon kopiertobj1
werden, werden ihre Ordnungen im Klon beibehalten , da bereits vorhandene Eigenschaften einfach überschrieben werden.quelle
In Node.js können Sie das native verwenden
require("assert").deepStrictEqual
. Weitere Informationen: http://nodejs.org/api/assert.htmlZum Beispiel:
Ein weiteres Beispiel, das
true
/false
anstelle von Fehlern zurückgibt :quelle
Chai
hat diese Funktion auch. In seinem Fall werden Sie verwenden:var foo = { a: 1 }; var bar = { a: 1 }; expect(foo).to.deep.equal(bar); // true;
error.name
zu"AssertionError [ERR_ASSERTION]"
. In diesem Fall würde ich die if-Anweisung durch ersetzenif (error.code === 'ERR_ASSERTION') {
.deepStrictEqual
wie es weitergehen sollte. Ich hatte mir den Kopf zerbrochen, um herauszufinden, warumstrictEqual
es nicht funktionierte. Fantastisch.Einfachste und logischste Lösungen zum Vergleichen von Objekten wie Objekt, Array, String, Int ...
JSON.stringify({a: val1}) === JSON.stringify({a: val2})
Hinweis:
val1
undval2
mit Ihrem Objekt ersetzenquelle
JSON.stringify
, eine alphabetische Neuordnung erfolgt? (Was ich nicht dokumentiert finden kann .)Ich verwende diese
comparable
Funktion, um Kopien meiner Objekte zu erstellen, die mit JSON vergleichbar sind:Ist praktisch in Tests (die meisten Test-Frameworks haben eine
is
Funktion). Z.BWenn ein Unterschied festgestellt wird, werden Zeichenfolgen protokolliert, wodurch Unterschiede erkennbar werden:
quelle
Hier ist eine Lösung in ES6 / ES2015, die einen funktionalen Ansatz verwendet:
Demo hier verfügbar
quelle
Ich weiß nicht, ob jemand etwas Ähnliches gepostet hat, aber hier ist eine Funktion, die ich gemacht habe, um nach Objektgleichheiten zu suchen.
Außerdem ist es rekursiv, sodass es auch auf tiefe Gleichheit prüfen kann, wenn Sie es so nennen.
quelle
Für diejenigen unter Ihnen, die NodeJS verwenden, gibt es eine praktische Methode, die
isDeepStrictEqual
für die native Util-Bibliothek aufgerufen wird, um dies zu erreichen.https://nodejs.org/api/util.html#util_util_isdeepstrictequal_val1_val2
quelle
ES6: Der Mindestcode, den ich dafür bekommen könnte, ist dieser. Es führt einen tiefen rekursiven Vergleich durch, indem alle Objekte stringifiziert werden. Die einzige Einschränkung besteht darin, dass keine Methoden oder Symbole verglichen werden.
quelle
Sie können
_.isEqual(obj1, obj2)
aus der Bibliothek underscore.js verwenden.Hier ist ein Beispiel:
Die offizielle Dokumentation finden Sie hier: http://underscorejs.org/#isEqual
quelle
Angenommen, die Reihenfolge der Eigenschaften im Objekt wird nicht geändert.
JSON.stringify () funktioniert für beide Objekttypen tief und nicht tief, wobei die Leistungsaspekte nicht sehr sicher sind:
quelle
Eine einfache Lösung für dieses Problem, die viele Menschen nicht erkennen, besteht darin, die JSON-Zeichenfolgen (pro Zeichen) zu sortieren. Dies ist normalerweise auch schneller als die anderen hier genannten Lösungen:
Eine weitere nützliche Sache bei dieser Methode ist, dass Sie Vergleiche filtern können, indem Sie eine "Ersetzer" -Funktion an die JSON.stringify-Funktionen übergeben ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON) / stringify # Example_of_using_replacer_parameter ). Im Folgenden werden nur alle Objektschlüssel mit dem Namen "derp" verglichen:
quelle
areEqual({a: 'b'}, {b: 'a'})
bekommttrue
dann?Ich wollte nur meine Version des Objektvergleichs mit einigen es6-Funktionen beitragen. Eine Bestellung wird nicht berücksichtigt. Nachdem ich alle if / else's in ternary konvertiert habe, bin ich mit folgendem Ergebnis gekommen:
quelle
Ich brauchte eine allgemeinere Objektvergleichsfunktion als veröffentlicht und habe mir Folgendes ausgedacht. Kritik geschätzt ...
quelle
Object.prototype
- in den allermeisten Fällen wird davon abgeraten (Ergänzungen werden beispielsweise in allen for..in-Schleifen angezeigt). Vielleicht überlegenObject.equals = function(aObj, bObj) {...}
?Wenn Sie JSON-Objekte vergleichen, können Sie https://github.com/mirek/node-rus-diff verwenden
Verwendungszweck:
Wenn zwei Objekte unterschiedlich sind, wird ein MongoDB-kompatibles
{$rename:{...}, $unset:{...}, $set:{...}}
Objekt zurückgegeben.quelle
Ich stand vor dem gleichen Problem und beschloss, meine eigene Lösung zu schreiben. Da ich aber auch Arrays mit Objekten vergleichen möchte und umgekehrt, habe ich eine generische Lösung entwickelt. Ich habe beschlossen, die Funktionen zum Prototyp hinzuzufügen, aber man kann sie leicht in eigenständige Funktionen umschreiben. Hier ist der Code:
Dieser Algorithmus ist in zwei Teile unterteilt. Die Funktion equals selbst und eine Funktion zum Ermitteln des numerischen Index einer Eigenschaft in einem Array / Objekt. Die Suchfunktion wird nur benötigt, weil indexof nur Zahlen und Zeichenfolgen und keine Objekte findet.
Man kann es so nennen:
Die Funktion gibt entweder true oder false zurück, in diesem Fall true. Der Algorithmus ermöglicht auch den Vergleich zwischen sehr komplexen Objekten:
Das obere Beispiel gibt true zurück, obwohl die Eigenschaften eine andere Reihenfolge haben. Ein kleines Detail, auf das Sie achten sollten: Dieser Code sucht auch nach demselben Typ von zwei Variablen, sodass "3" nicht mit 3 identisch ist.
quelle
Ich sehe Spaghetti-Code-Antworten. Ohne die Verwendung von Bibliotheken von Drittanbietern ist dies sehr einfach.
Sortieren Sie zunächst die beiden Objekte nach Schlüssel und Schlüsselnamen.
Verwenden Sie dann einfach eine Zeichenfolge, um sie zu vergleichen.
quelle
Ich würde von Hashing oder Serialisierung abraten (wie die JSON-Lösung vorschlägt). Wenn Sie testen müssen, ob zwei Objekte gleich sind, müssen Sie definieren, was gleich bedeutet. Es kann sein, dass alle Datenelemente in beiden Objekten übereinstimmen, oder dass die Speicherorte übereinstimmen müssen (dh beide Variablen verweisen auf dasselbe Objekt im Speicher), oder dass nur ein Datenelement in jedem Objekt übereinstimmen muss.
Kürzlich habe ich ein Objekt entwickelt, dessen Konstruktor bei jeder Erstellung einer Instanz eine neue ID erstellt (beginnend mit 1 und inkrementierend um 1). Dieses Objekt verfügt über eine isEqual-Funktion, die diesen ID-Wert mit dem ID-Wert eines anderen Objekts vergleicht und true zurückgibt, wenn sie übereinstimmen.
In diesem Fall habe ich "gleich" so definiert, dass die ID-Werte übereinstimmen. Da jede Instanz eine eindeutige ID hat, kann dies verwendet werden, um die Idee durchzusetzen, dass übereinstimmende Objekte ebenfalls denselben Speicherort belegen. Obwohl das nicht nötig ist.
quelle
Es ist nützlich, zwei Objekte als gleich zu betrachten, wenn sie für alle Eigenschaften dieselben Werte und für alle verschachtelten Objekte und Arrays rekursiv haben. Ich betrachte auch die folgenden zwei Objekte als gleich:
Ebenso können Arrays "fehlende" Elemente und undefinierte Elemente enthalten. Ich würde diese auch gleich behandeln:
Eine Funktion, die diese Definition von Gleichheit implementiert:
Quellcode (einschließlich der Hilfsfunktionen generalType und uniqueArray): Unit Test und Test Runner hier .
quelle
Ich mache mit dieser Funktion folgende Annahmen:
Dies sollte als Demonstration einer einfachen Strategie betrachtet werden.
quelle
Dies ist eine Ergänzung für alle oben genannten, kein Ersatz. Wenn Sie Objekte mit flachem Vergleich schnell vergleichen müssen, ohne zusätzliche rekursive Fälle überprüfen zu müssen. Hier ist ein Schuss.
Dies ist vergleichbar mit: 1) Gleichheit der Anzahl der eigenen Eigenschaften, 2) Gleichheit der Schlüsselnamen, 3) wenn bCompareValues == true, Gleichheit der entsprechenden Eigenschaftswerte und ihrer Typen (dreifache Gleichheit)
quelle
Zum Vergleichen von Schlüsseln für Objektinstanzen mit einfachen Schlüssel / Wert-Paaren verwende ich:
Sobald die Schlüssel verglichen sind, reicht eine einfache zusätzliche
for..in
Schleife aus.Die Komplexität ist O (N * N), wobei N die Anzahl der Schlüssel ist.
Ich hoffe / vermute, dass Objekte, die ich definiere, nicht mehr als 1000 Eigenschaften enthalten ...
quelle
Ich weiß, dass dies ein bisschen alt ist, aber ich möchte eine Lösung hinzufügen, die ich für dieses Problem gefunden habe. Ich hatte ein Objekt und wollte wissen, wann sich seine Daten geändert haben. "etwas ähnliches wie Object.observe" und was ich getan habe war:
Dies hier kann dupliziert werden und ein anderer Satz von Arrays erstellt werden, um die Werte und Schlüssel zu vergleichen. Dies ist sehr einfach, da sie jetzt Arrays sind und false zurückgeben, wenn Objekte unterschiedliche Größen haben.
quelle
false
, da Arrays nicht nach Wert verglichen werden, z[1,2] != [1,2]
.