Tengo dos objetos: oldObj
y newObj
.
Los datos oldObj
se utilizaron para completar un formulario y newObj
es el resultado de que el usuario haya cambiado los datos en este formulario y los haya enviado.
Ambos objetos son profundos, es decir. tienen propiedades que son objetos o matrices de objetos, etc., pueden tener n niveles de profundidad, por lo tanto, el algoritmo diff debe ser recursivo.
Ahora necesito no solo averiguar qué se cambió (como agregado / actualizado / eliminado) de oldObj
a newObj
, sino también cómo representarlo mejor.
Hasta ahora, mis pensamientos eran simplemente construir un genericDeepDiffBetweenObjects
método que devolviera un objeto en el formulario, {add:{...},upd:{...},del:{...}}
pero luego pensé: alguien más debe haber necesitado esto antes.
Entonces ... ¿alguien sabe de una biblioteca o un fragmento de código que haga esto y tal vez tenga una forma aún mejor de representar la diferencia (de una manera que todavía es serializable JSON)?
Actualizar:
He pensado en una mejor manera de representar los datos actualizados, utilizando la misma estructura de objeto newObj
, pero convirtiendo todos los valores de propiedad en objetos en el formulario:
{type: '<update|create|delete>', data: <propertyValue>}
Entonces, newObj.prop1 = 'new value'
y oldObj.prop1 = 'old value'
estableceríareturnObj.prop1 = {type: 'update', data: 'new value'}
Actualización 2:
Se vuelve realmente difícil cuando llegamos a las propiedades que son matrices, ya que la matriz [1,2,3]
debe contarse como igual a [2,3,1]
, que es lo suficientemente simple para las matrices de tipos basados en valores como string, int & bool, pero se vuelve realmente difícil de manejar cuando se trata de matrices de tipos de referencia como objetos y matrices.
Ejemplos de matrices que deberían ser iguales:
[1,[{c: 1},2,3],{a:'hey'}] and [{a:'hey'},1,[3,{c: 1},2]]
No solo es bastante complejo verificar este tipo de igualdad de valores profundos, sino también encontrar una buena manera de representar los cambios que podrían ocurrir.
fuente
newObj
es generado por el código js que lee valores de un formulario en el DOM. Hay varias formas de mantener el estado y hacerlo mucho más fácil, pero me gustaría mantenerlo sin estado como ejercicio. También estoy buscando arte previo para ver cómo otros podrían haber abordado esto, si es que alguien lo ha hecho.Respuestas:
Escribí una pequeña clase que está haciendo lo que quieres, puedes probarla aquí .
Lo único que es diferente de su propuesta es que no considero
[1,[{c: 1},2,3],{a:'hey'}] and [{a:'hey'},1,[3,{c: 1},2]]
que sea igual, porque creo que las matrices no son iguales si el orden de sus elementos no es el mismo. Por supuesto, esto se puede cambiar si es necesario. Además, este código se puede mejorar aún más para tomar la función como argumento que se utilizará para formatear el objeto diff de manera arbitraria en función de los valores primitivos pasados (ahora este trabajo se realiza mediante el método "compareValues").fuente
c
se crea comoundefined
, pero debe ser la cadena'i am created'
), y además no hace lo que necesito ya que le falta el valor de matriz profunda comparar que es el parte más crucial (y compleja / difícil). Como nota al margen, la construcción'array' != typeof(obj)
es inútil ya que las matrices son objetos que son instancias de matrices.{type: ..., data:..}
objeto? Lo que falta es buscar el valor de la primera matriz en la segunda, pero como mencioné en mi respuesta, no creo que las matrices sean iguales si el orden de sus valores no es igual ([1, 2, 3] is not equal to [3, 2, 1]
en mi opinión).[{key: 'value1'}] and [{key: 'value2'}, {key: 'value3'}]
. Ahora es el primer objeto en la primera matriz actualizado con "valor1" o "valor2". Y este es un ejemplo simple, podría complicarse mucho con el anidamiento profundo. Si usted quiere / necesita la comparación de profundidad de anidamiento independientemente de la posición clave no crean matrices de objetos, crear objetos con objetos anidados, como por ejemplo anterior:{inner: {key: 'value1'}} and {inner: {key: 'value2'}, otherInner: {key: 'value3'}}
.Usando Underscore, un simple diff:
Resultados en las partes de
o1
que corresponden pero con diferentes valores eno2
:Sería diferente para una diferencia profunda:
Como señaló @Juhana en los comentarios, lo anterior es solo una diferencia a -> b y no reversible (lo que significa que las propiedades adicionales en b serían ignoradas). Utilice en su lugar a -> b -> a:
Ver http://jsfiddle.net/drzaus/9g5qoxwj/ para ver ejemplos completos + pruebas + mixins
fuente
omit
que sería una gran diferencia, pero estaba equivocado, así que también lo incluí para comparar.r[k] = ... : v
enr[k] = ... : {'a':v, 'b':b[k] }
, de esta manera se pueden ver dos valores.{a:1, b:2}
y{a:1, b:2, c:3}
._.omitBy
lugar de_.omit
.Me gustaría ofrecer una solución ES6 ... Esta es una diferencia unidireccional, lo que significa que devolverá claves / valores
o2
que no son idénticos a sus contrapartes eno1
:fuente
if(o1[key] === o1[key])
línea amigoUncaught SyntaxError: Unexpected token ...
Usando Lodash:
No uso clave / objeto / fuente, pero lo dejé allí si necesita acceder a ellos. La comparación de objetos simplemente evita que la consola imprima las diferencias en la consola desde el elemento más externo hasta el elemento más interno.
Puede agregar algo de lógica dentro para manejar matrices. Quizás clasifique las matrices primero. Esta es una solución muy flexible.
EDITAR
Cambió de _.merge a _.mergeWith debido a la actualización lodash. Gracias Aviron por notar el cambio.
fuente
Aquí hay una biblioteca de JavaScript que puede usar para encontrar diferencias entre dos objetos de JavaScript:
URL de Github: https://github.com/cosmicanant/recursive-diff
URL de Npmjs: https://www.npmjs.com/package/recursive-diff
Puede usar la biblioteca recursive-diff en el navegador, así como Node.js. Para el navegador, haga lo siguiente:
Mientras que en node.js puede requerir el módulo 'recursive-diff' y usarlo como a continuación:
fuente
En estos días, hay bastantes módulos disponibles para esto. Recientemente escribí un módulo para hacer esto, porque no estaba satisfecho con los numerosos módulos diferentes que encontré. Se llama
odiff
: https://github.com/Tixit/odiff . También enumeré un montón de los módulos más populares y por qué no eran aceptables en el archivo Léameodiff
, que podría consultar siodiff
no tiene las propiedades que desea. Aquí hay un ejemplo:fuente
Hay un módulo npm con más de 500k descargas semanales: https://www.npmjs.com/package/deep-object-diff
Me gusta el objeto como representación de las diferencias, especialmente es fácil ver la estructura, cuando está formateada.
fuente
He usado este código para realizar la tarea que usted describe:
esto le dará un nuevo objeto que combinará todos los cambios entre el objeto antiguo y el nuevo objeto de su formulario
fuente
$.extend(true,obj1,obj2)
usar jQuery. Esto no es para nada lo que necesito. Necesito la diferencia entre los dos objetos, no la combinación de ellos.Desarrollé la función llamada "compareValue ()" en Javascript. devuelve si el valor es igual o no. He llamado a compareValue () en el bucle for de un Object. Puede obtener la diferencia de dos objetos en diffParams.
fuente
Sé que llego tarde a la fiesta, pero necesitaba algo similar que las respuestas anteriores no ayudaron.
Estaba usando la función $ watch de Angular para detectar cambios en una variable. No solo necesitaba saber si una propiedad había cambiado en la variable, sino que también quería asegurarme de que la propiedad que cambió no era un campo calculado temporal. En otras palabras, quería ignorar ciertas propiedades.
Aquí está el código: https://jsfiddle.net/rv01x6jo/
Aquí se explica cómo usarlo:
Espero que esto ayude a alguien.
fuente
Solo uso ramda, para resolver el mismo problema, necesito saber qué cambia en el nuevo objeto. Entonces aquí mi diseño.
El resultado es el nombre de la propiedad y su estado.
fuente
Aquí hay una versión mecanografiada del código @sbgoran
fuente
Aquí hay una versión modificada de algo encontrado en gisthub .
fuente
Modifiqué la respuesta de @ sbgoran para que el objeto diff resultante incluya solo los valores modificados y omita los valores que eran iguales. Además, muestra tanto el valor original como el valor actualizado .
fuente
Ya escribí una función para uno de mis proyectos que comparará un objeto como opciones de usuario con su clon interno. También puede validar e incluso reemplazar por valores predeterminados si el usuario ingresó un tipo de datos incorrecto o lo eliminó, en javascript puro.
En IE8 100% funciona. Probado con éxito.
/ * resultado
fuente
La función más extendida y simplificada de la respuesta de sbgoran.
Esto permite un escaneo profundo y encuentra la similitud de una matriz.
fuente
Me tropecé aquí tratando de buscar una manera de obtener la diferencia entre dos objetos. Esta es mi solución usando Lodash:
fuente
Tomé la respuesta anterior de @sbgoran y la modifiqué para mi caso igual que la pregunta necesaria, para tratar las matrices como conjuntos (es decir, el orden no es importante para diff)
fuente
Aquí hay una solución que es:
object
tipo)undefined
Primero definimos la interfaz de resultados de comparación:
con el caso especial de cambio donde queremos saber cuáles son los valores antiguos y nuevos:
Entonces podemos proporcionar la
diff
función que es simplemente dos bucles (con recursividad sideep
estrue
):Como ejemplo, llamando a:
volverá:
y llamando al mismo con el
deep
tercer parámetro devolverá:fuente
Esta biblioteca es una de las más rápidas para crear diferencias de objetos profundos:
https://www.npmjs.com/package/@netilon/differify
fuente