995 Stimmen

Wie bestimmt man die Gleichheit zweier JavaScript-Objekte?

Ein strikter Gleichheitsoperator sagt Ihnen, ob zwei Objekte Typen gleich sind. Gibt es jedoch eine Möglichkeit zu erkennen, ob zwei Objekte gleich sind, ähnlich wie der Hash-Code Wert in Java?

Stack Overflow Frage Gibt es irgendeine Art von HashCode-Funktion in JavaScript? ist dieser Frage ähnlich, erfordert aber eine eher akademische Antwort. Das obige Szenario zeigt, warum es notwendig wäre, eine zu haben, und ich frage mich, ob es irgendeine gleichwertige Lösung .

5 Stimmen

Gehen Sie auch dieser Frage nach stackoverflow.com/q/1068834/1671639

55 Stimmen

Beachten Sie, dass auch in Java, a.hashCode() == b.hashCode() tut no bedeuten, dass a ist gleich b . Das ist eine notwendige, aber keine hinreichende Bedingung.

7 Stimmen

Wenn Sie Objekte in Ihrem Code vergleichen MÜSSEN, dann haben Sie Ihren Code wahrscheinlich falsch geschrieben. Die bessere Frage könnte lauten: "Wie kann ich diesen Code so schreiben, dass ich keine Objekte vergleichen muss?"

4voto

Ich habe eine einfache Möglichkeit gefunden, die Werte von zwei Javascript-Objekten ohne Berücksichtigung der Eigentumsordnung ist mit der Funktion JSON stringify replacer:

const compareReplacer = (key, value) => {
    if(typeof value === 'object' && !(value instanceof Array))
        return Object.entries(value).sort();
    return value;
}
export const compareObjects = (a, b) => JSON.stringify(a, compareReplacer) === JSON.stringify(b, compareReplacer);

Dadurch werden die Eigenschaften bei jedem Schritt geordnet, so dass das Ergebnis der Zeichenkette nicht von der Reihenfolge der Eigenschaften abhängt. Jemand hat wahrscheinlich dies vor getan, aber ich dachte nur, ich würde es teilen, falls nicht :).

4voto

th317erd Punkte 314

EDIT: Diese Methode ist ziemlich mangelhaft und birgt ihre eigenen Probleme. Ich empfehle sie nicht und würde mich über einige Ablehnungen freuen! Sie ist problematisch, weil 1) einige Dinge nicht verglichen werden können (z.B. Funktionen), weil sie nicht serialisiert werden können, 2) es ist keine sehr schnelle Vergleichsmethode, 3) es gibt Probleme mit der Reihenfolge, 4) es kann Kollisionsprobleme/falsch-positive Ergebnisse geben, wenn es nicht richtig implementiert ist, 5) es kann nicht auf "Exaktheit" geprüft werden ( === ) und basiert stattdessen auf der Gleichheit der Werte, was oft nicht das ist, was bei einer Vergleichsmethode erwünscht ist.

Eine einfache Lösung für dieses Problem, die viele Leute nicht kennen, ist die Sortierung der JSON-Strings (nach Zeichen). Dies ist in der Regel auch schneller als die anderen hier genannten Lösungen:

function areEqual(obj1, obj2) {
    var a = JSON.stringify(obj1), b = JSON.stringify(obj2);
    if (!a) a = '';
    if (!b) b = '';
    return (a.split('').sort().join('') == b.split('').sort().join(''));
}

Ein weiterer nützlicher Aspekt dieser Methode ist, dass Sie Vergleiche filtern können, indem Sie eine "Replacer"-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 verglichen, die den Namen "derp" tragen:

function areEqual(obj1, obj2, filter) {
    var a = JSON.stringify(obj1, filter), b = JSON.stringify(obj2, filter);
    if (!a) a = '';
    if (!b) b = '';
    return (a.split('').sort().join('') == b.split('').sort().join(''));
}
var equal = areEqual(obj1, obj2, function(key, value) {
    return (key === 'derp') ? value : undefined;
});

1 Stimmen

Oh, ich habe auch vergessen, dass die Funktion beschleunigt werden kann, indem man zuerst prüft, ob die Objekte gleich sind und frühzeitig abbricht, wenn sie das gleiche Objekt sind: if (obj1 === obj2) return true;

14 Stimmen

areEqual({a: 'b'}, {b: 'a'}) erhält true dann?

0 Stimmen

Ja, ich habe nach meinem Beitrag gemerkt, dass diese "Lösung" Probleme hat. Es braucht ein bisschen mehr Arbeit in den Sortieralgorithmus, um tatsächlich richtig zu funktionieren.

3voto

Sir_baaron Punkte 325

Ich stand vor demselben Problem und beschloss, meine eigene Lösung zu schreiben. Da ich aber auch Arrays mit Objekten und umgekehrt vergleichen möchte, habe ich eine generische Lösung entwickelt. Ich beschloss, die Funktionen zum Prototyp hinzuzufügen, aber man kann sie leicht in eigenständige Funktionen umschreiben. Hier ist der Code:

Array.prototype.equals = Object.prototype.equals = function(b) {
    var ar = JSON.parse(JSON.stringify(b));
    var err = false;
    for(var key in this) {
        if(this.hasOwnProperty(key)) {
            var found = ar.find(this[key]);
            if(found > -1) {
                if(Object.prototype.toString.call(ar) === "[object Object]") {
                    delete ar[Object.keys(ar)[found]];
                }
                else {
                    ar.splice(found, 1);
                }
            }
            else {
                err = true;
                break;
            }
        }
    };
    if(Object.keys(ar).length > 0 || err) {
        return false;
    }
    return true;
}

Array.prototype.find = Object.prototype.find = function(v) {
    var f = -1;
    for(var i in this) {
        if(this.hasOwnProperty(i)) {
            if(Object.prototype.toString.call(this[i]) === "[object Array]" || Object.prototype.toString.call(this[i]) === "[object Object]") {
                if(this[i].equals(v)) {
                    f = (typeof(i) == "number") ? i : Object.keys(this).indexOf(i);
                }
            }
            else if(this[i] === v) {
                f = (typeof(i) == "number") ? i : Object.keys(this).indexOf(i);
            }
        }
    }
    return f;
}

Dieser Algorithmus besteht aus zwei Teilen: der Gleichheitsfunktion selbst und einer Funktion zum Auffinden des numerischen Index einer Eigenschaft in einem Array/Objekt. Die find-Funktion wird nur benötigt, weil indexof nur Zahlen und Strings und keine Objekte findet.

Man kann es auch so nennen:

({a: 1, b: "h"}).equals({a: 1, b: "h"});

Die Funktion gibt entweder true oder false zurück, in diesem Fall true. Der Algorithmus ermöglicht auch den Vergleich zwischen sehr komplexen Objekten:

({a: 1, b: "hello", c: ["w", "o", "r", "l", "d", {answer1: "should be", answer2: true}]}).equals({b: "hello", a: 1, c: ["w", "d", "o", "r", {answer1: "should be", answer2: true}, "l"]})

Das obere Beispiel gibt true zurück, auch wenn die Eigenschaften eine andere Reihenfolge haben. Ein kleines Detail, auf das Sie achten sollten: Dieser Code prüft auch, ob zwei Variablen den gleichen Typ haben, also ist "3" nicht dasselbe wie 3.

3voto

Mirek Rusin Punkte 17854

Wenn Sie JSON-Objekte vergleichen, können Sie https://github.com/mirek/node-rus-diff

npm install rus-diff

使用方法

a = {foo:{bar:1}}
b = {foo:{bar:1}}
c = {foo:{bar:2}}

var rusDiff = require('rus-diff').rusDiff

console.log(rusDiff(a, b)) // -> false, meaning a and b are equal
console.log(rusDiff(a, c)) // -> { '$set': { 'foo.bar': 2 } }

Wenn zwei Objekte unterschiedlich sind, wird eine MongoDB-kompatible {$rename:{...}, $unset:{...}, $set:{...}} wie ein Objekt zurückgegeben.

3voto

Sergiy Seletskyy Punkte 14714

Wie kann man feststellen, dass das Teilobjekt (Partial<T>) gleich dem Originalobjekt (T) in typescript ist.

function compareTwoObjects<T>(original: T, partial: Partial<T>): boolean {
  return !Object.keys(partial).some((key) => partial[key] !== original[key]);
}

P.S. Ursprünglich hatte ich vor, eine neue Frage mit einer Antwort zu erstellen. Aber eine solche Frage existiert bereits und wurde als Duplikat markiert.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X