Wie kann ich die Gleichheit von zwei JavaScript-Objekten bestimmen?
Ein strenger Gleichheitsoperator wird Ihnen sagen, ob zwei Objekttypen gleich sind. Gibt es jedoch eine Möglichkeit festzustellen, ob zwei Objekte gleich sind, ähnlich wie der Hash-Code-Wert in Java?
Die Stack-Overflow-Frage Gibt es irgendeine Art von hashCode-Funktion in JavaScript? ist dieser Frage ähnlich, erfordert jedoch eine wissenschaftlichere Antwort. Das oben beschriebene Szenario zeigt, warum es notwendig wäre, eine solche zu haben, und ich frage mich, ob es eine äquivalente Lösung gibt.
Antwort #1
Warum das Rad neu erfinden? Probieren Sie Lodash aus. Es hat eine Reihe von unverzichtbaren Funktionen wie isEqual().
_.isEqual(object, other);
Es wird jeden Schlüsselwert mit Brute-Force überprüfen - genau wie die anderen Beispiele auf dieser Seite - unter Verwendung von ECMAScript 5 und nativen Optimierungen, wenn sie im Browser verfügbar sind.
Hinweis: In einer früheren Version empfahl diese Antwort Underscore.js, aber lodash hat bessere Arbeit geleistet, um Fehler zu beheben und Probleme mit der Konsistenz anzugehen.
Antwort #2
Die kurze Antwort
Die einfache Antwort lautet: Nein, es gibt kein generisches Mittel, um festzustellen, dass ein Objekt in dem von Ihnen gemeinten Sinne einem anderen gleich ist. Die Ausnahme ist, wenn Sie strikt daran denken, dass ein Objekt typelos ist.
Die lange Antwort
Das Konzept ist das einer Equals-Methode, die zwei verschiedene Instanzen eines Objekts vergleicht, um anzuzeigen, ob sie auf Wert-Ebene gleich sind. Es liegt jedoch am spezifischen Typ, zu definieren, wie eine Equals-Methode implementiert werden sollte. Ein iterativer Vergleich von Attributen mit primitiven Werten ist möglicherweise nicht ausreichend: Ein Objekt kann Attribute enthalten, die für die Gleichheit nicht relevant sind. Zum Beispiel,
function MyClass(a, b)
{
var c;
this.getCLazy = function() {
if (c === undefined) c = a * b // imagine * is really expensive
return c;
}
}
In dem oben genannten Fall ist c nicht wirklich wichtig, um zu bestimmen, ob zwei Instanzen von MyClass gleich sind, nur a und b sind wichtig. In einigen Fällen kann c zwischen Instanzen variieren und dennoch beim Vergleich nicht bedeutend sein.
Beachten Sie, dass dieses Problem auftritt, wenn Mitglieder selbst auch Instanzen eines Typs sein können und jeder von ihnen eine Möglichkeit benötigt, Gleichheit zu bestimmen.
Weiter kompliziert wird die Sache dadurch, dass in JavaScript die Unterscheidung zwischen Daten und Methode verschwommen ist.
Ein Objekt kann auf eine Methode verweisen, die als Ereignis-Handler aufgerufen werden soll, und dies würde wahrscheinlich nicht als Teil seines ‚Wertzustands‘ betrachtet werden. Während einem anderen Objekt gut eine Funktion zugewiesen werden kann, die eine wichtige Berechnung ausführt und dadurch diese Instanz von anderen unterscheidet, einfach weil sie auf eine andere Funktion verweist.
Wie wäre es mit einem Objekt, bei dem eine seiner vorhandenen Prototypmethoden durch eine andere Funktion überschrieben wurde? Könnte es trotzdem als gleich zu einer anderen Instanz betrachtet werden, die sonst identisch ist? Diese Frage kann nur in jedem spezifischen Fall für jeden Typ beantwortet werden.
Wie bereits erwähnt, wäre die Ausnahme ein strikt typenloses Objekt. In diesem Fall ist die einzige vernünftige Wahl ein iterativer und rekursiver Vergleich jedes einzelnen Elements. Selbst dann muss man sich fragen, was der 'Wert' einer Funktion ist?
Antwort #3
Der Standard-Gleichheitsoperator in JavaScript für Objekte liefert true, wenn sie auf denselben Speicherort verweisen.
var x = {};
var y = {};
var z = x;
x === y; // => false
x === z; // => true
Wenn Sie einen anderen Gleichheitsoperator benötigen, müssen Sie eine equals(other)-Methode oder etwas Ähnliches zu Ihren Klassen hinzufügen, und die Besonderheiten Ihres Problemfeldes werden bestimmen, was genau das bedeutet.
Hier ist ein Beispiel für eine Spielkarte:
function Card(rank, suit) {
this.rank = rank;
this.suit = suit;
this.equals = function(other) {
return other.rank == this.rank && other.suit == this.suit;
};
}
var queenOfClubs = new Card(12, "C");
var kingOfSpades = new Card(13, "S");
queenOfClubs.equals(kingOfSpades); // => false
kingOfSpades.equals(new Card(13, "S")); // => true
Antwort #4
Kurze funktionale deepEqual-Implementierung:
function deepEqual(x, y) {
return (x && y && typeof x === 'object' && typeof y === 'object') ?
(Object.keys(x).length === Object.keys(y).length) &&
Object.keys(x).reduce(function(isEqual, key) {
return isEqual && deepEqual(x[key], y[key]);
}, true) : (x === y);
}
Bearbeiten: Version 2, unter Verwendung von Jibs Vorschlag und ES6-Pfeilfunktionen:
function deepEqual(x, y) {
const ok = Object.keys, tx = typeof x, ty = typeof y;
return x && y && tx === 'object' && tx === ty ? (
ok(x).length === ok(y).length &&
ok(x).every(key => deepEqual(x[key], y[key]))
) : (x === y);
}
Antwort #5
Dies ist meine Version. Sie verwendet die neue Object.keys-Funktion, die in ES5 eingeführt wurde, sowie Ideen/Tests von +, + und +:
function objectEquals(x, y) {
'use strict';
if (x === null || x === undefined || y === null || y === undefined) { return x === y; }
// after this just checking type of one would be enough
if (x.constructor !== y.constructor) { return false; }
// if they are functions, they should exactly refer to same one (because of closures)
if (x instanceof Function) { return x === y; }
// if they are regexps, they should exactly refer to same one (it is hard to better equality check on current ES)
if (x instanceof RegExp) { return x === y; }
if (x === y || x.valueOf() === y.valueOf()) { return true; }
if (Array.isArray(x) && x.length !== y.length) { return false; }
// if they are dates, they must had equal valueOf
if (x instanceof Date) { return false; }
// if they are strictly equal, they both need to be object at least
if (!(x instanceof Object)) { return false; }
if (!(y instanceof Object)) { return false; }
// recursive object equality check
var p = Object.keys(x);
return Object.keys(y).every(function (i) { return p.indexOf(i) !== -1; }) &&
p.every(function (i) { return objectEquals(x[i], y[i]); });
}
///////////////////////////////////////////////////////////////
/// 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(null,null));
assert.isFalse(objectEquals(null,undefined));
assert.isFalse(objectEquals(/abc/, /abc/));
assert.isFalse(objectEquals(/abc/, /123/));
var r = /abc/;
assert.isTrue(objectEquals(r, r));
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}}));
Object.prototype.equals = function (obj) { return objectEquals(this, obj); };
var assertFalse = assert.isFalse,
assertTrue = assert.isTrue;
assertFalse({}.equals(null));
assertFalse({}.equals(undefined));
assertTrue("hi".equals("hi"));
assertTrue(new Number(5).equals(5));
assertFalse(new Number(5).equals(10));
assertFalse(new Number(1).equals("1"));
assertTrue([].equals([]));
assertTrue([1,2].equals([1,2]));
assertFalse([1,2].equals([2,1]));
assertFalse([1,2].equals([1,2,3]));
assertTrue(new Date("2011-03-31").equals(new Date("2011-03-31")));
assertFalse(new Date("2011-03-31").equals(new Date("1970-01-01")));
assertTrue({}.equals({}));
assertTrue({a:1,b:2}.equals({a:1,b:2}));
assertTrue({a:1,b:2}.equals({b:2,a:1}));
assertFalse({a:1,b:2}.equals({a:1,b:3}));
assertTrue({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}.equals({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}));
assertFalse({1:{name:"mhc",age:28}, 2:{name:"arb",age:26}}.equals({1:{name:"mhc",age:28}, 2:{name:"arb",age:27}}));
var a = {a: 'text', b:[0,1]};
var b = {a: 'text', b:[0,1]};
var c = {a: 'text', b: 0};
var d = {a: 'text', b: false};
var e = {a: 'text', b:[1,0]};
var i = {
a: 'text',
c: {
b: [1, 0]
}
};
var j = {
a: 'text',
c: {
b: [1, 0]
}
};
var k = {a: 'text', b: null};
var l = {a: 'text', b: undefined};
assertTrue(a.equals(b));
assertFalse(a.equals(c));
assertFalse(c.equals(d));
assertFalse(a.equals(e));
assertTrue(i.equals(j));
assertFalse(d.equals(k));
assertFalse(k.equals(l));
// from comments on stackoverflow post
assert.isFalse(objectEquals([1, 2, undefined], [1, 2]));
assert.isFalse(objectEquals([1, 2, 3], { 0: 1, 1: 2, 2: 3 }));
assert.isFalse(objectEquals(new Date(1234), 1234));
// no two different function is equal really, they capture their context variables
// so even if they have same toString(), they won't have same functionality
var func = function (x) { return true; };
var func2 = function (x) { return true; };
assert.isTrue(objectEquals(func, func));
assert.isFalse(objectEquals(func, func2));
assert.isTrue(objectEquals({ a: { b: func } }, { a: { b: func } }));
assert.isFalse(objectEquals({ a: { b: func } }, { a: { b: func2 } }));Antwort #6
Wenn Sie mit AngularJS arbeiten, wird die Funktion angular.equals feststellen, ob zwei Objekte gleich sind. In Ember.js verwenden Sie isEqual.
angular.equals- Siehe die Dokumentation oder den Quelltext für mehr Informationen zu dieser Methode. Sie führt auch einen tiefgehenden Vergleich von Arrays durch.- Ember.js
isEqual- Siehe die Dokumentation oder den Quellcode, um mehr über diese Methode zu erfahren. Es wird kein tiefer Vergleich von Arrays durchgeführt.
var purple = [{"purple": "drank"}];
var drank = [{"purple": "drank"}];
if(angular.equals(purple, drank)) {
document.write('got dat');
}<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>Antwort #7
Wenn Sie eine JSON-Bibliothek verwenden, können Sie jedes Objekt als JSON kodieren und dann die resultierenden Zeichenketten auf Gleichheit vergleichen.
var obj1={test:"value"};
var obj2={test:"value2"};
alert(JSON.encode(obj1)===JSON.encode(obj2));
HINWEIS: Obwohl diese Antwort in vielen Fällen funktionieren wird, ist sie, wie mehrere Personen in den Kommentaren festgestellt haben, aus verschiedenen Gründen problematisch. In fast allen Fällen möchten Sie eine robustere Lösung finden.
Antwort #8
Für diejenigen unter Ihnen, die Node verwenden, gibt es eine praktische Methode namens isDeepStrictEqual in der nativen util-Bibliothek, die dies erreichen kann.
const util = require('util');
const obj1 = {
foo: "bar",
baz: [1, 2]
};
const obj2 = {
foo: "bar",
baz: [1, 2]
};
obj1 == obj2 // false
util.isDeepStrictEqual(obj1, obj2) // true
https://nodejs.org/api/util.html#util_util_isdeepstrictequal_val1_val2
Antwort #9
In Node.js können Sie das native require("assert").deepStrictEqual verwenden. Mehr Informationen: http://nodejs.org/api/assert.html
Zum Beispiel:
var assert = require("assert");
assert.deepStrictEqual({a:1, b:2}, {a:1, b:3}); // will throw AssertionError
Ein weiteres Beispiel, das true/false zurückgibt, anstatt Fehler zurückzugeben:
var assert = require("assert");
function deepEqual(a, b) {
try {
assert.deepEqual(a, b);
} catch (error) {
if (error.name === "AssertionError") {
return false;
}
throw error;
}
return true;
};
Antwort #10
Diese Frage hat bereits mehr als 30 Antworten. Ich werde sie zusammenfassen und erklären (mit einer "mein Vater"-Analogie) und meine vorgeschlagene Lösung hinzufügen.
Sie haben 4+1 Klassen von Lösungen:
1) Verwenden Sie eine hacky unvollständige schnelle Einzeiler-Lösung
Gut, wenn Sie es eilig haben und 99% Genauigkeit ausreichen.
Beispiele dafür sind JSON.stringify(), vorgeschlagen von Pratik Bhalodiya, oder JSON.encode von Joel Anair, oder .toString(), oder andere Methoden, die Ihre Objekte in einen String umwandeln und dann die beiden Strings Zeichen für Zeichen mit === vergleichen.
Der Nachteil ist jedoch, dass es keine weltweit standardisierte eindeutige Darstellung eines Objekts als String gibt. Zum Beispiel sind { a: 5, b: 8} und {b: 8 und a: 5 } gleich.
- Vorteile: Schnell, zügig.
- Nachteile: Hoffentlich funktioniert es! Es wird nicht funktionieren, wenn die Umgebung/der Browser/die Engine die Reihenfolge von Objekten speichert (z. B. Chrome/V8) und die Reihenfolge der Schlüssel unterschiedlich ist (Danke an Eksapsy). Also überhaupt nicht garantiert. Die Leistung wäre auch bei großen Objekten nicht besonders gut.
Mein Vater Analogie
Wenn ich über meinen Vater spreche, sind „mein großer gutaussehender Vater“ und „mein gutaussehender großer Vater“ dieselbe Person! Aber die beiden Zeichenketten sind nicht gleich.
Beachten Sie, dass es tatsächlich eine richtige (Standard-)Reihenfolge von Adjektiven in der englischen Grammatik gibt, die besagt, dass es ein „gutaussehender großer Mann“ sein sollte, aber Sie riskieren Ihre Kompetenz, wenn Sie blind davon ausgehen, dass die Javascript-Engine von iOS 8 Safari dieselbe Grammatik ebenfalls einhält, blind! #WillkommenBeiJavascriptNichtStandards
2) Schreibe deine eigene DIY-Rekursionsfunktion
Gut, wenn du lernst.
Beispiele sind atmins Lösung.
Der größte Nachteil ist, dass Sie definitiv einige Randfälle verpassen werden. Haben Sie eine Selbstreferenz in Objektwerten in Betracht gezogen? Haben Sie NaN in Betracht gezogen? Haben Sie zwei Objekte in Betracht gezogen, die die gleichen ownProperties haben, aber unterschiedliche prototypische Eltern?
Ich würde Menschen nur ermutigen, dies zu tun, wenn sie üben und der Code nicht in die Produktion geht. Das ist der einzige Fall, in dem es eine Rechtfertigung dafür gibt, das Rad neu zu erfinden.
- Vorteile: Lernmöglichkeit.
- Contra: Nicht zuverlässig. Nimmt Zeit und verursacht Sorgen.
Mein Vater Analogie
Es ist, als würde man annehmen, dass, wenn der Name meines Vaters „John Smith“ ist und sein Geburtstag der „1.1.1970“ ist, dann jeder, dessen Name „John Smith“ ist und der am „1.1.1970“ geboren wurde, mein Vater ist.
Das ist normalerweise der Fall, aber was ist, wenn es an diesem Tag zwei "John Smiths" gibt? Wenn Sie denken, dass Sie ihre Größe berücksichtigen werden, dann erhöht das die Genauigkeit, ist aber immer noch kein perfekter Vergleich.
2.1 Ihr begrenzter DIY-Komparator
Anstatt einer wilden Verfolgung nach dem rekursiven Überprüfen aller Eigenschaften, könnte man in Betracht ziehen, nur eine „begrenzte“ Anzahl von Eigenschaften zu überprüfen. Zum Beispiel, wenn die Objekte Users sind, kann man deren emailAddress-Feld vergleichen.
Es ist immer noch nicht perfekt, aber die Vorteile gegenüber Lösung #2 sind:
- Es ist vorhersehbar, und es ist weniger wahrscheinlich, dass es abstürzt.
- Sie treiben die „Definition“ von Gleichheit voran, anstatt sich auf eine wilde Form und Gestalt des Objekts und seines Prototyps sowie verschachtelte Eigenschaften zu verlassen.
3) Verwende eine Bibliotheksversion der equal-Funktion
Gut, wenn Sie eine Produktionsqualität benötigen und das Design des Systems nicht ändern können.
Beispiele sind _.equal von lodash, bereits in coolaj86s Antwort oder Angulars oder Embers wie in Tony Harveys Antwort erwähnt oder Nodes von Rafael Xavier.
- Vorteile: Es ist das, was alle anderen tun.
- Nachteile: Externe Abhängigkeit, die zusätzliche Speicher-/CPU-/Sicherheitsbedenken verursachen kann, auch wenn nur ein wenig. Außerdem kann sie immer noch einige Randfälle übersehen (z. B. ob zwei Objekte mit denselben
eigenenEigenschaftenaber unterschiedlichen prototypischen Eltern als gleich betrachtet werden sollten oder nicht). Schließlich, könnten Sie unbeabsichtigt ein zugrunde liegendes Designproblem damit provisorisch kaschieren; nur so als Hinweis!
Mein Vater Analogie
Es ist wie eine Agentur zu bezahlen, um meinen biologischen Vater zu finden, basierend auf seinem Telefon, Namen, Adresse usw.
Es wird mehr kosten, und es ist wahrscheinlich genauer als wenn ich selbst die Hintergrundüberprüfung durchführe, aber es deckt keine Randfälle ab, wie zum Beispiel wenn mein Vater Einwanderer/Asylant ist und sein Geburtsdatum unbekannt ist!
4) Verwenden Sie einen Bezeichner im Objekt
Gut, wenn Sie das Design des Systems (der Objekte, mit denen Sie arbeiten) [noch] ändern können und möchten, dass Ihr Code lange hält.
Es ist nicht in allen Fällen anwendbar und möglicherweise nicht sehr leistungsfähig. Es ist jedoch eine sehr zuverlässige Lösung, wenn Sie es umsetzen können.
Die Lösung besteht darin, dass jedes Objekt im System eine eindeutige Kennung zusammen mit allen anderen Eigenschaften haben wird. Die Eindeutigkeit der Kennung wird zum Zeitpunkt der Generierung garantiert. Und Sie werden diese ID (auch bekannt als UUID/GUID -- Global/Universally Unique Identifier) verwenden, wenn es darum geht, zwei Objekte zu vergleichen. Das heißt, sie sind gleich, wenn und nur wenn diese IDs gleich sind.
Die IDs können einfache auto_incremental-Zahlen sein oder ein String, der über eine Bibliothek (empfohlen) oder ein Stück Code erzeugt wird. Alles, was Sie tun müssen, ist sicherzustellen, dass sie immer eindeutig sind, was im Fall von auto_incremental eingebaut sein kann oder im Fall von UUID mit allen vorhandenen Werten überprüft werden kann (z. B. über MySQLs UNIQUE-Spaltenattribut) oder einfach (wenn sie aus einer Bibliothek stammen) auf die extrem geringe Wahrscheinlichkeit einer Kollision verlassen werden kann.
Beachten Sie, dass Sie die ID jederzeit zusammen mit dem Objekt speichern müssen (um ihre Einzigartigkeit zu gewährleisten), und es ist möglicherweise nicht die beste Vorgehensweise, sie in Echtzeit zu berechnen.
- Vorteile: Zuverlässig, effizient, nicht schmutzig, modern.
- Nachteile: Benötigt zusätzlichen Platz. Möglicherweise ist eine Neugestaltung des Systems erforderlich.
Mein Vater Analogie
Es ist, als wüsste man, dass die Sozialversicherungsnummer meines Vaters 911-345-9283 ist, also ist jeder, der diese SSN hat, mein Vater, und jeder, der behauptet, mein Vater zu sein, muss diese SSN haben.
Fazit
Ich persönlich bevorzuge Lösung #4 (ID) allen anderen vor allem aufgrund von Genauigkeit und Zuverlässigkeit. Wenn das nicht möglich ist, würde ich #2.1 wegen der Vorhersagbarkeit wählen und dann #3. Wenn keine davon möglich ist, #2 und schließlich #1.
Antwort #11
Versuchst du zu testen, ob zwei Objekte gleich sind? Also: ob ihre Eigenschaften gleich sind?
Wenn dies der Fall ist, haben Sie diese Situation wahrscheinlich bemerkt:
var a = { foo : "bar" };
var b = { foo : "bar" };
alert (a == b ? "Equal" : "Not equal");
// "Not equal"
Du könntest so etwas tun müssen:
function objectEquals(obj1, obj2) {
for (var i in obj1) {
if (obj1.hasOwnProperty(i)) {
if (!obj2.hasOwnProperty(i)) return false;
if (obj1[i] != obj2[i]) return false;
}
}
for (var i in obj2) {
if (obj2.hasOwnProperty(i)) {
if (!obj1.hasOwnProperty(i)) return false;
if (obj1[i] != obj2[i]) return false;
}
}
return true;
}
Offensichtlich könnte diese Funktion eine ziemlich umfassende Optimierung gebrauchen und die Fähigkeit zum tiefgehenden Überprüfen (um verschachtelte Objekte zu handhaben: var a={ foo : { fu : "bar" } }), aber Sie verstehen die Idee.
Wie FOR hervorgehoben hat, müssen Sie dies möglicherweise für Ihre eigenen Zwecke anpassen, z. B.: verschiedene Klassen können unterschiedliche Definitionen von „gleich“ haben. Wenn Sie nur mit einfachen Objekten arbeiten, kann das Obige ausreichend sein, andernfalls könnte eine benutzerdefinierte MyClass.equals()-Funktion der richtige Weg sein.
Antwort #12
var object1 = {name: "humza" , gender : "male", age: 23}
var object2 = {name: "humza" , gender : "male", age: 23}
var result = Object.keys(object1).every((key) => object1[key] === object2[key])
Das Ergebnis wird true sein, wenn object1 dieselben Werte wie object2 hat.
Antwort #13
Wenn Sie eine Funktion für tiefe Kopien zur Hand haben, können Sie den folgenden Trick verwenden, um trotzdem JSON.stringify zu verwenden und gleichzeitig die Reihenfolge der Eigenschaften beizubehalten:
function equals(obj1, obj2) {
function _equals(obj1, obj2) {
return JSON.stringify(obj1)
=== JSON.stringify($.extend(true, {}, obj1, obj2));
}
return _equals(obj1, obj2) && _equals(obj2, obj1);
}
Demo: http://jsfiddle.net/CU3vb/3/
Begründung:
Da die Eigenschaften von obj1 einzeln in die Kopie übernommen werden, wird ihre Reihenfolge in der Kopie beibehalten. Und wenn die Eigenschaften von obj2 in die Kopie übernommen werden, werden bereits in obj1 vorhandene Eigenschaften einfach überschrieben, wodurch ihre Reihenfolge in der Kopie beibehalten wird.
Antwort #14
Einfachste und logische Lösungen zum Vergleichen von allem wie Objekt, Array, String, Int...
JSON.stringify({a: val1}) === JSON.stringify({a: val2})Hinweis :
- Sie müssen
val1undval2durch Ihr Objekt ersetzen - Für das Objekt müssen Sie beide Seitenobjekte rekursiv nach dem Schlüssel sortieren.
Antwort #15
Ich benutze diese comparable-Funktion, um Kopien meiner Objekte zu erstellen, die JSON-vergleichbar sind:
var comparable = o => (typeof o != 'object' || !o)? o :
Object.keys(o).sort().reduce((c, key) => (c[key] = comparable(o[key]), c), {});
// Demo:
var a = { a: 1, c: 4, b: [2, 3], d: { e: '5', f: null } };
var b = { b: [2, 3], c: 4, d: { f: null, e: '5' }, a: 1 };
console.log(JSON.stringify(comparable(a)));
console.log(JSON.stringify(comparable(b)));
console.log(JSON.stringify(comparable(a)) == JSON.stringify(comparable(b)));<div id="div"></div>Kommt bei Tests gelegen (die meisten Testframeworks haben eine is-Funktion). Z.B.
is(JSON.stringify(comparable(x)), JSON.stringify(comparable(y)), 'x must match y');
Wenn ein Unterschied festgestellt wird, werden Zeichenketten protokolliert, wodurch Unterschiede erkennbar werden:
x must match y
got {"a":1,"b":{"0":2,"1":3},"c":7,"d":{"e":"5","f":null}},
expected {"a":1,"b":{"0":2,"1":3},"c":4,"d":{"e":"5","f":null}}.
Antwort #16
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
Antwort #17
Ich weiß nicht, ob schon jemand etwas Ähnliches dazu gepostet hat, aber hier ist eine Funktion, die ich erstellt habe, um Objektgleichheiten zu überprü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;
}
Also, es ist rekursiv, sodass es auch auf tiefe Gleichheit prüfen kann, wenn man es so nennen will.
