Ich habe zwei Objekte: oldObj
und newObj
.
Die Daten in oldObj
wurden zum Auffüllen eines Formulars verwendet und newObj
sind das Ergebnis der Änderung und Übermittlung der Daten in diesem Formular durch den Benutzer.
Beide Objekte sind tief, dh. Sie haben Eigenschaften, die Objekte oder Arrays von Objekten usw. sind. Sie können n Ebenen tief sein, daher muss der Diff-Algorithmus rekursiv sein.
Jetzt muss ich nicht nur herauszufinden , was geändert wurde (wie in hinzugefügt / aktualisiert / gelöscht) aus oldObj
zu newObj
, sondern auch , wie man am besten repräsentieren sie.
Bisher dachte ich nur daran, eine genericDeepDiffBetweenObjects
Methode zu erstellen , die ein Objekt auf dem Formular {add:{...},upd:{...},del:{...}}
zurückgibt, aber dann dachte ich: Jemand anderes muss das schon einmal gebraucht haben.
Also ... kennt jemand eine Bibliothek oder einen Code, der dies tut und vielleicht eine noch bessere Möglichkeit hat, den Unterschied darzustellen (auf eine Weise, die immer noch JSON-serialisierbar ist)?
Aktualisieren:
Ich habe mir eine bessere Möglichkeit überlegt, die aktualisierten Daten darzustellen, indem ich dieselbe Objektstruktur wie verwende newObj
, aber alle Eigenschaftswerte in Objekte im Formular umwandle:
{type: '<update|create|delete>', data: <propertyValue>}
Also wenn newObj.prop1 = 'new value'
und oldObj.prop1 = 'old value'
es würde setzenreturnObj.prop1 = {type: 'update', data: 'new value'}
Update 2:
Es wird wirklich haarig, wenn wir zu Eigenschaften kommen, die Arrays sind, da das Array [1,2,3]
als gleich gezählt werden sollte [2,3,1]
, was für Arrays von wertbasierten Typen wie string, int & bool einfach genug ist, aber wirklich schwierig zu handhaben ist, wenn es darum geht Arrays von Referenztypen wie Objekte und Arrays.
Beispielarrays, die gleich gefunden werden sollten:
[1,[{c: 1},2,3],{a:'hey'}] and [{a:'hey'},1,[3,{c: 1},2]]
Es ist nicht nur recht komplex, nach dieser Art von tiefer Wertgleichheit zu suchen, sondern auch einen guten Weg zu finden, um die möglichen Änderungen darzustellen.
quelle
newObj
wird durch js Code generiert, der Werte aus einem Formular im DOM liest. Es gibt verschiedene Möglichkeiten, den Zustand beizubehalten und dies viel einfacher zu tun, aber ich möchte ihn als Übung staatenlos halten. Ich suche auch nach dem Stand der Technik, um zu sehen, wie andere dies angegangen sein könnten, wenn es tatsächlich jemand getan hat.Antworten:
Ich habe eine kleine Klasse geschrieben, die macht, was Sie wollen. Sie können sie hier testen .
Das einzige, was sich von Ihrem Vorschlag unterscheidet, ist, dass ich es nicht als
[1,[{c: 1},2,3],{a:'hey'}] and [{a:'hey'},1,[3,{c: 1},2]]
gleich betrachte, weil ich denke, dass Arrays nicht gleich sind, wenn die Reihenfolge ihrer Elemente nicht gleich ist. Dies kann natürlich bei Bedarf geändert werden. Auch dieser Code kann weiter verbessert werden, um als Argument zu fungieren, das zum willkürlichen Formatieren von diff-Objekten basierend auf übergebenen primitiven Werten verwendet wird (jetzt wird diese Aufgabe mit der Methode "compareValues" ausgeführt).quelle
c
wird als Zeichenfolge erstelltundefined
, sollte es aber sein'i am created'
), und außerdem macht es nicht das, was ich brauche, da es an dem Vergleich des tiefen Array-Werts mangelt wichtigster (und komplexester / schwieriger) Teil. Als Randnotiz ist das Konstrukt'array' != typeof(obj)
nutzlos, da Arrays Objekte sind, die Instanzen von Arrays sind.{type: ..., data:..}
Objekts erhalten. Was fehlt, ist die Suche nach dem Wert des ersten Arrays im zweiten, aber wie ich in meiner Antwort erwähnt habe, denke ich nicht, dass Arrays gleich sind, wenn die Reihenfolge ihrer Werte nicht gleich ist ([1, 2, 3] is not equal to [3, 2, 1]
meiner Meinung nach).[{key: 'value1'}] and [{key: 'value2'}, {key: 'value3'}]
. Jetzt wird das erste Objekt im ersten Array mit "Wert1" oder "Wert2" aktualisiert. Und dies ist ein einfaches Beispiel, es könnte beim tiefen Verschachteln sehr kompliziert werden. Wenn Sie einen tiefen Verschachtelungsvergleich unabhängig von der Schlüsselposition wünschen / benötigen, erstellen Sie keine Arrays von Objekten. Erstellen Sie Objekte mit verschachtelten Objekten wie im vorherigen Beispiel :{inner: {key: 'value1'}} and {inner: {key: 'value2'}, otherInner: {key: 'value3'}}
.Mit Unterstrich ein einfacher Unterschied:
Die Ergebnisse in den Teilen
o1
entsprechen, jedoch mit unterschiedlichen Werten ino2
:Für einen tiefen Unterschied wäre es anders:
Wie von @Juhana in den Kommentaren hervorgehoben, ist das Obige nur ein Unterschied a -> b und nicht reversibel (was bedeutet, dass zusätzliche Eigenschaften in b ignoriert würden). Verwenden Sie stattdessen a -> b -> a:
Ein vollständiges Beispiel + Tests + Mixins finden Sie unter http://jsfiddle.net/drzaus/9g5qoxwj/
quelle
omit
wäre ein tiefer Unterschied, aber es war falsch, also auch zum Vergleich.r[k] = ... : v
inr[k] = ... : {'a':v, 'b':b[k] }
, auf diese Weise Sie zwei Werte sehen.{a:1, b:2}
und{a:1, b:2, c:3}
._.omitBy
statt sein_.omit
.Ich möchte eine ES6-Lösung anbieten ... Dies ist ein Einweg-Diff, was bedeutet, dass Schlüssel / Werte zurückgegeben werden
o2
, die nicht mit denen in identisch sind ino1
:quelle
if(o1[key] === o1[key])
Linie Kerl überprüfenUncaught SyntaxError: Unexpected token ...
Verwenden von Lodash:
Ich verwende keinen Schlüssel / Objekt / Quelle, aber ich habe ihn dort belassen, wenn Sie darauf zugreifen müssen. Der Objektvergleich verhindert lediglich, dass die Konsole die Unterschiede vom äußersten zum innersten Element auf die Konsole druckt.
Sie können eine Logik hinzufügen, um Arrays zu verarbeiten. Vielleicht sortieren Sie zuerst die Arrays. Dies ist eine sehr flexible Lösung.
BEARBEITEN
Geändert von _.merge zu _.mergeWith aufgrund eines lodash-Updates. Vielen Dank an Aviron, dass Sie die Änderung bemerkt haben.
quelle
Hier ist eine JavaScript-Bibliothek, mit der Sie Unterschiede zwischen zwei JavaScript-Objekten finden können:
Github-URL: https://github.com/cosmicanant/recursive-diff
Npmjs URL: https://www.npmjs.com/package/recursive-diff
Sie können die rekursive Diff-Bibliothek sowohl im Browser als auch in Node.js verwenden. Gehen Sie für den Browser wie folgt vor:
In node.js können Sie das Modul 'recursive-diff' benötigen und es wie folgt verwenden:
quelle
Heutzutage stehen dafür einige Module zur Verfügung. Ich habe kürzlich ein Modul dazu geschrieben, weil ich mit den zahlreichen unterschiedlichen Modulen, die ich gefunden habe, nicht zufrieden war. Es heißt
odiff
: https://github.com/Tixit/odiff . Ich habe auch eine Reihe der beliebtesten Module aufgelistet und erklärt, warum sie in der Readme-Datei von nicht akzeptabel waren. Sie können sie durchsehenodiff
, wennodiff
sie nicht die gewünschten Eigenschaften haben. Hier ist ein Beispiel:quelle
Es gibt ein npm-Modul mit über 500.000 wöchentlichen Downloads: https://www.npmjs.com/package/deep-object-diff
Ich mag die objektähnliche Darstellung der Unterschiede - besonders ist es leicht, die Struktur zu sehen, wenn sie formatiert ist.
quelle
Ich habe diesen Code für die von Ihnen beschriebene Aufgabe verwendet:
Dadurch erhalten Sie ein neues Objekt, das alle Änderungen zwischen dem alten und dem neuen Objekt aus Ihrem Formular zusammenführt
quelle
$.extend(true,obj1,obj2)
Verwendung von jQuery durchgeführt werden. Das brauche ich überhaupt nicht. Ich brauche den Unterschied zwischen den beiden Objekten, nicht die Kombination von ihnen.Ich habe die Funktion "compareValue ()" in Javascript entwickelt. Es wird zurückgegeben, ob der Wert gleich ist oder nicht. Ich habe compareValue () in der for-Schleife eines Objekts aufgerufen. In diffParams können Sie zwei Objekte unterscheiden.
quelle
Ich weiß, dass ich zu spät zur Party komme, aber ich brauchte etwas Ähnliches, dass die obigen Antworten nicht geholfen haben.
Ich habe Angulars $ watch-Funktion verwendet, um Änderungen in einer Variablen zu erkennen. Ich musste nicht nur wissen, ob sich eine Eigenschaft für die Variable geändert hat, sondern auch sicherstellen, dass die geänderte Eigenschaft kein temporäres, berechnetes Feld ist. Mit anderen Worten, ich wollte bestimmte Eigenschaften ignorieren.
Hier ist der Code: https://jsfiddle.net/rv01x6jo/
So verwenden Sie es:
Hoffe das hilft jemandem.
quelle
Ich benutze nur Ramda, um das gleiche Problem zu lösen, muss ich wissen, was in neuen Objekten geändert wird. Also hier mein Design.
Ergebnis ist, Name der Eigenschaft und deren Status.
quelle
Hier ist eine maschinengeschriebene Version des @ sbgoran-Codes
quelle
Hier ist eine modifizierte Version von etwas, das auf gisthub gefunden wurde .
quelle
Ich habe die Antwort von @ sbgoran so geändert, dass das resultierende Diff-Objekt nur die geänderten Werte enthält und dieselben Werte weglässt. Außerdem werden sowohl der ursprüngliche als auch der aktualisierte Wert angezeigt .
quelle
Ich habe bereits eine Funktion für eines meiner Projekte geschrieben, mit der ein Objekt als Benutzeroption mit seinem internen Klon verglichen wird. Es kann auch Standardwerte validieren und sogar ersetzen, wenn der Benutzer einen falschen Datentyp eingegeben oder in reinem Javascript entfernt hat.
In IE8 funktioniert 100%. Erfolgreich getestet.
/ * Ergebnis
quelle
Die erweiterte und vereinfachte Funktion aus sbgorans Antwort.
Dies ermöglicht ein tiefes Scannen und das Finden der Ähnlichkeit eines Arrays.
quelle
Ich bin hier gestolpert und habe versucht, einen Weg zu finden, um den Unterschied zwischen zwei Objekten zu erkennen. Dies ist meine Lösung mit Lodash:
quelle
Ich nahm die obige Antwort von @sbgoran und änderte sie für meinen Fall genauso wie die benötigte Frage, um Arrays als Mengen zu behandeln (dh die Reihenfolge ist für diff nicht wichtig).
quelle
Hier ist eine Lösung:
object
Typ)undefined
Zuerst definieren wir die Schnittstelle für Vergleichsergebnisse:
mit dem speziellen Fall der Veränderung, in dem wir wissen wollen, was alte und neue Werte sind:
Dann können wir die
diff
Funktion bereitstellen, die lediglich zwei Schleifen sind (mit Rekursivität, wenn dies der Falldeep
isttrue
):Als Beispiel rufen Sie an:
wird zurückkehren:
Wenn Sie dasselbe mit dem
deep
dritten Parameter aufrufen, wird Folgendes zurückgegeben:quelle
Diese Bibliothek ist eine der schnellsten, um tiefe Objektunterschiede zu machen:
https://www.npmjs.com/package/@netilon/differify
quelle