J'ai deux objets: oldObj
et newObj
.
Les données dans ont oldObj
été utilisées pour remplir un formulaire et newObj
sont le résultat de la modification des données de l'utilisateur dans ce formulaire et de leur soumission.
Les deux objets sont profonds, ie. ils ont des propriétés qui sont des objets ou des tableaux d'objets, etc. - ils peuvent avoir une profondeur de n niveaux, donc l'algorithme diff doit être récursif.
Maintenant , je dois non seulement comprendre ce qui a changé (comme ajoutée / mise à jour / supprimé) de oldObj
la newObj
, mais aussi la meilleure façon de le représenter.
Jusqu'à présent, je pensais simplement construire une genericDeepDiffBetweenObjects
méthode qui retournerait un objet sur le formulaire, {add:{...},upd:{...},del:{...}}
mais j'ai pensé: quelqu'un d'autre devait en avoir besoin auparavant.
Alors ... quelqu'un connaît-il une bibliothèque ou un morceau de code qui fera cela et peut-être a-t-il une meilleure façon de représenter la différence (d'une manière qui est encore sérialisable JSON)?
Mettre à jour:
J'ai pensé à une meilleure façon de représenter les données mises à jour, en utilisant la même structure d'objet que newObj
, mais en transformant toutes les valeurs de propriété en objets sur le formulaire:
{type: '<update|create|delete>', data: <propertyValue>}
Donc , si newObj.prop1 = 'new value'
et oldObj.prop1 = 'old value'
il fixeraitreturnObj.prop1 = {type: 'update', data: 'new value'}
Mise à jour 2:
Cela devient vraiment poilu lorsque nous arrivons à des propriétés qui sont des tableaux, car le tableau [1,2,3]
doit être compté comme égal à [2,3,1]
, ce qui est assez simple pour les tableaux de types basés sur des valeurs comme string, int & bool, mais devient vraiment difficile à gérer en ce qui concerne tableaux de types de référence comme des objets et des tableaux.
Exemples de tableaux qui doivent être trouvés égaux:
[1,[{c: 1},2,3],{a:'hey'}] and [{a:'hey'},1,[3,{c: 1},2]]
Non seulement il est assez complexe de vérifier ce type d'égalité de valeur profonde, mais aussi de trouver un bon moyen de représenter les changements qui pourraient être.
la source
newObj
est généré par le code js qui lit les valeurs d'un formulaire dans le DOM. Il y a plusieurs façons de garder l'état et de le faire beaucoup plus facilement, mais j'aimerais le garder apatride comme exercice. Je suis également à la recherche d'antériorités pour voir comment d'autres auraient pu résoudre ce problème, si quelqu'un l'a fait.Réponses:
J'ai écrit un petit cours qui fait ce que tu veux, tu peux le tester ici .
La seule chose qui est différente de votre proposition est que je ne considère
[1,[{c: 1},2,3],{a:'hey'}] and [{a:'hey'},1,[3,{c: 1},2]]
pas la même chose, car je pense que les tableaux ne sont pas égaux si l'ordre de leurs éléments n'est pas le même. Bien sûr, cela peut être modifié si nécessaire. De plus, ce code peut être encore amélioré pour prendre la fonction comme argument qui sera utilisé pour formater un objet diff de manière arbitraire en fonction des valeurs primitives passées (maintenant ce travail est effectué par la méthode "compareValues").la source
c
est créé commeundefined
mais devrait être la chaîne'i am created'
), et en plus il ne fait pas ce dont j'ai besoin car il manque la valeur du tableau profond comparer qui est le partie la plus cruciale (et complexe / difficile). En remarque, la construction'array' != typeof(obj)
est inutile car les tableaux sont des objets qui sont des instances de tableaux.{type: ..., data:..}
objet. Ce qui manque, c'est la recherche de la valeur du premier tableau dans le second, mais comme je l'ai mentionné dans ma réponse, je ne pense pas que les tableaux soient égaux si l'ordre de leurs valeurs n'est pas égal ([1, 2, 3] is not equal to [3, 2, 1]
à mon avis).[{key: 'value1'}] and [{key: 'value2'}, {key: 'value3'}]
. Le premier objet du premier tableau est maintenant mis à jour avec "valeur1" ou "valeur2". Et ceci est un exemple simple, cela pourrait devenir beaucoup plus compliqué avec une imbrication profonde. Si vous voulez / besoin comparaison profonde imbrication indépendamment de la position clé ne créent pas des tableaux d'objets, créer des objets avec des objets imbriqués comme par exemple précédent:{inner: {key: 'value1'}} and {inner: {key: 'value2'}, otherInner: {key: 'value3'}}
.En utilisant Underscore, un simple diff:
Les résultats dans les parties de
o1
cela correspondent mais avec des valeurs différentes danso2
:Ce serait différent pour une différence profonde:
Comme souligné par @Juhana dans les commentaires, ce qui précède n'est qu'un diff a -> b et non réversible (ce qui signifie que les propriétés supplémentaires dans b seraient ignorées). Utilisez plutôt a -> b -> a:
Voir http://jsfiddle.net/drzaus/9g5qoxwj/ pour un exemple complet + tests + mixins
la source
omit
serait une différence profonde, mais j'avais tort, donc inclus également à des fins de comparaison.r[k] = ... : v
der[k] = ... : {'a':v, 'b':b[k] }
cette façon, vous pouvez voir deux valeurs.{a:1, b:2}
et{a:1, b:2, c:3}
._.omitBy
au lieu de_.omit
.J'aimerais offrir une solution ES6 ... Il s'agit d'un différentiel à sens unique, ce qui signifie qu'il retournera des clés / valeurs
o2
qui ne sont pas identiques à leurs homologues danso1
:la source
if(o1[key] === o1[key])
ligne mecUncaught SyntaxError: Unexpected token ...
Utilisation de Lodash:
Je n'utilise pas de clé / objet / source mais je l'ai laissé là si vous avez besoin d'y accéder. La comparaison d'objets empêche simplement la console d'imprimer les différences sur la console de l'élément le plus externe à l'élément le plus interne.
Vous pouvez ajouter un peu de logique à l'intérieur pour gérer les tableaux. Peut-être triez les tableaux en premier. Il s'agit d'une solution très flexible.
ÉDITER
Modifié de _.merge à _.mergeWith en raison de la mise à jour de lodash. Merci à Aviron d'avoir remarqué le changement.
la source
Voici une bibliothèque JavaScript que vous pouvez utiliser pour rechercher des différences entre deux objets JavaScript:
URL Github: https://github.com/cosmicanant/recursive-diff
URL Npmjs: https://www.npmjs.com/package/recursive-diff
Vous pouvez utiliser la bibliothèque récursive-diff dans le navigateur ainsi que Node.js. Pour le navigateur, procédez comme suit:
Alors que dans node.js, vous pouvez avoir besoin d'un module 'récursif-diff' et l'utiliser comme ci-dessous:
la source
De nos jours, il y a pas mal de modules disponibles pour cela. J'ai récemment écrit un module pour ce faire, car je n'étais pas satisfait des nombreux modules différents que j'ai trouvés. Son appelé
odiff
: https://github.com/Tixit/odiff . J'ai également énuméré un tas des modules les plus populaires et pourquoi ils n'étaient pas acceptables dans le fichier Lisez-odiff
moi, que vous pouvez consulter siodiff
vous n'avez pas les propriétés souhaitées. Voici un exemple:la source
Il existe un module npm avec plus de 500 000 téléchargements hebdomadaires: https://www.npmjs.com/package/deep-object-diff
J'aime l'objet comme la représentation des différences - surtout il est facile de voir la structure, quand elle est formatée.
la source
J'ai utilisé ce morceau de code pour effectuer la tâche que vous décrivez:
cela vous donnera un nouvel objet qui fusionnera toutes les modifications entre l'ancien objet et le nouvel objet de votre formulaire
la source
$.extend(true,obj1,obj2)
utiliser jQuery. Ce n'est pas du tout ce dont j'ai besoin. J'ai besoin de la différence entre les deux objets et non de leur combinaison.J'ai développé la fonction nommée "compareValue ()" en Javascript. il retourne si la valeur est identique ou non. J'ai appelé compareValue () dans la boucle for d'un objet. vous pouvez obtenir la différence de deux objets dans diffParams.
la source
Je sais que je suis en retard à la fête, mais j'avais besoin de quelque chose de similaire que les réponses ci-dessus n'ont pas aidé.
J'utilisais la fonction $ watch d'Angular pour détecter les changements dans une variable. Non seulement je devais savoir si une propriété avait changé sur la variable, mais je voulais également m'assurer que la propriété qui avait changé n'était pas un champ calculé temporaire. En d'autres termes, je voulais ignorer certaines propriétés.
Voici le code: https://jsfiddle.net/rv01x6jo/
Voici comment l'utiliser:
J'espère que cela aide quelqu'un.
la source
J'utilise juste ramda, pour résoudre le même problème, j'ai besoin de savoir ce qui est changé dans le nouvel objet. Voici donc ma conception.
le résultat est, le nom de la propriété et son statut.
la source
Voici une version dactylographiée du code @sbgoran
la source
Voici une version modifiée de quelque chose trouvé sur gisthub .
la source
J'ai modifié la réponse de @ sbgoran afin que l'objet diff résultant n'inclue que les valeurs modifiées et omet les valeurs identiques. En outre, il affiche à la fois la valeur d'origine et la valeur mise à jour .
la source
J'ai déjà écrit une fonction pour l'un de mes projets qui comparera un objet en tant qu'options utilisateur avec son clone interne. Il peut également valider et même remplacer par des valeurs par défaut si l'utilisateur a entré un mauvais type de données ou supprimé, en pur javascript.
Dans IE8 100% fonctionne. Testé avec succès.
/* résultat
la source
La fonction plus étendue et simplifiée de la réponse de sbgoran.
Cela permet une analyse approfondie et de trouver la simillarité d'un tableau.
la source
Je suis tombé ici en essayant de chercher un moyen de faire la différence entre deux objets. Voici ma solution en utilisant Lodash:
la source
J'ai pris la réponse ci-dessus par @sbgoran et l'ai modifiée pour mon cas comme la question nécessaire, pour traiter les tableaux comme des ensembles (c'est-à-dire que l'ordre n'est pas important pour diff)
la source
Voici une solution qui est:
object
type)undefined
Nous définissons d'abord l'interface du résultat de la comparaison:
avec le cas particulier du changement où nous voulons savoir quelles sont les anciennes et les nouvelles valeurs:
Ensuite, nous pouvons fournir la
diff
fonction qui n'est que deux boucles (avec récursivité sideep
c'est le castrue
):Par exemple, en appelant:
retournera:
et l'appelant avec le
deep
troisième paramètre renverra:la source
Cette bibliothèque est l'une des plus rapides pour faire des différences d'objets profonds:
https://www.npmjs.com/package/@netilon/differify
la source