1020 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

56 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?"

13voto

Alan R. Soares Punkte 1625

Hier ist eine Lösung in ES6/ES2015 mit einem funktionalen Ansatz:

const typeOf = x => 
  ({}).toString
      .call(x)
      .match(/\[object (\w+)\]/)[1]

function areSimilar(a, b) {
  const everyKey = f => Object.keys(a).every(f)

  switch(typeOf(a)) {
    case 'Array':
      return a.length === b.length &&
        everyKey(k => areSimilar(a.sort()[k], b.sort()[k]));
    case 'Object':
      return Object.keys(a).length === Object.keys(b).length &&
        everyKey(k => areSimilar(a[k], b[k]));
    default:
      return a === b;
  }
}

Demo hier verfügbar

0 Stimmen

Funktioniert nicht, wenn sich die Reihenfolge der Objektschlüssel geändert hat.

12voto

Zac Punkte 789

Ich weiß nicht, ob schon jemand etwas Ähnliches gepostet hat, aber hier ist eine Funktion, die ich gemacht habe, um auf Objektgleichheiten zu prüfen.

function objectsAreEqual(a, b) {
  for (var prop in a) {
    if (a.hasOwnProperty(prop)) {
      if (b.hasOwnProperty(prop)) {
        if (typeof a[prop] === 'object') {
          if (!objectsAreEqual(a[prop], b[prop])) return false;
        } else {
          if (a[prop] !== b[prop]) return false;
        }
      } else {
        return false;
      }
    }
  }
  return true;
}

Außerdem ist es rekursiv, so dass es auch auf tiefe Gleichheit prüfen kann, wenn Sie es so nennen.

0 Stimmen

Kleine Korrektur: bevor man die einzelnen Requisiten in a und b durchgeht, sollte man diese Prüfung hinzufügen if(Object.getOwnPropertyNames(a).length !== Object.getOwnPropertyNames(b).length ) return false

2 Stimmen

Ist es offensichtlich, dass ein geeigneter Gleichheitsprüfer rekursiv sein muss. Ich denke, dass eine dieser rekursiven Antworten die richtige Antwort sein sollte. Die akzeptierte Antwort enthält keinen Code und ist nicht hilfreich

8voto

Adriano Spadoni Punkte 3967

ES6: Der minimale Code, den ich hinbekommen könnte, ist dieser. Es tun tiefe Vergleich rekursiv durch stringifying alle Schlüssel-Wert-Array sortiert, die das Objekt, die einzige Einschränkung ist keine Methoden oder Symbole zu vergleichen sind.

const compareObjects = (a, b) => { 
  let s = (o) => Object.entries(o).sort().map(i => { 
     if(i[1] instanceof Object) i[1] = s(i[1]);
     return i 
  }) 
  return JSON.stringify(s(a)) === JSON.stringify(s(b))
}

console.log(compareObjects({b:4,a:{b:1}}, {a:{b:1},b:4}));

WICHTIG! Diese Funktion führt einen JSON.stringfy in einer ARRAY mit den sortierten Schlüsseln und PAS in dem Objekt selbst:

  1. ["a", ["b", 1]]
  2. ["b", 4]

0 Stimmen

Dies ist eine voll funktionsfähige Antwort, danke @Adriano Spadoni. Wissen Sie, wie ich den Schlüssel/das Attribut erhalten kann, der/das geändert wurde? Danke!

1 Stimmen

Hallo @digital, wenn Sie wissen wollen, welche Tasten unterschiedlich sind, ist dies nicht die ideale Funktion. Prüfen Sie die andere Antwort und verwenden Sie eine mit einer Schleife durch die Objekte.

0 Stimmen

Verwenden Sie niemals JSON.stringify, um json-Objekte zu vergleichen. Es wird nicht erwartet, dass die Reihenfolge der Schlüssel gleich ist.

6voto

Paul Punkte 4796

Nachfolgend finden Sie eine kurze Implementierung, bei der JSON.stringify aber sortiert die Schlüssel wie von @Jor vorgeschlagen aquí .

Einige Tests wurden aus der Antwort von @EbrahimByagowi übernommen aquí .

Natürlich, durch die Verwendung von JSON.stringify ist die Lösung auf JSON-serialisierbare Typen beschränkt (eine Zeichenkette, eine Zahl, ein JSON-Objekt, ein Array, ein Boolean, null). Objekte wie Date , Function usw. werden nicht unterstützt.

function objectEquals(obj1, obj2) {
  const JSONstringifyOrder = obj => {
    const keys = {};
    JSON.stringify(obj, (key, value) => {
      keys[key] = null;
      return value;
    });
    return JSON.stringify(obj, Object.keys(keys).sort());
  };
  return JSONstringifyOrder(obj1) === JSONstringifyOrder(obj2);
}

///////////////////////////////////////////////////////////////
/// The borrowed tests, run them by clicking "Run code snippet"
///////////////////////////////////////////////////////////////
var printResult = function (x) {
    if (x) { document.write('<div style="color: green;">Passed</div>'); }
    else { document.write('<div style="color: red;">Failed</div>'); }
};
var assert = { isTrue: function (x) { printResult(x); }, isFalse: function (x) { printResult(!x); } }

assert.isTrue(objectEquals("hi","hi"));
assert.isTrue(objectEquals(5,5));
assert.isFalse(objectEquals(5,10));

assert.isTrue(objectEquals([],[]));
assert.isTrue(objectEquals([1,2],[1,2]));
assert.isFalse(objectEquals([1,2],[2,1]));
assert.isFalse(objectEquals([1,2],[1,2,3]));

assert.isTrue(objectEquals({},{}));
assert.isTrue(objectEquals({a:1,b:2},{a:1,b:2}));
assert.isTrue(objectEquals({a:1,b:2},{b:2,a:1}));
assert.isFalse(objectEquals({a:1,b:2},{a:1,b:3}));

assert.isTrue(objectEquals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}},{1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}));
assert.isFalse(objectEquals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}},{1:{name:"mhc",age:28}, 2:{name:"arb",age:27}}));

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.

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