我有两个对象:oldObj和newObj。
oldObj中的数据用于填充表单,而newObj是用户更改该表单中的数据并提交的结果。
这两个物体都很深。它们具有对象或对象数组等属性-它们可以有n层深,因此diff算法需要递归。
现在我不仅需要弄清楚从oldObj到newObj更改了什么(如添加/更新/删除),而且还需要知道如何最好地表示它。
到目前为止,我的想法只是构建一个通用的deepdiffbetweenobjects方法,该方法将返回窗体上的对象{add:{…},upd:{…},del:{…但我转念一想:以前一定有人需要它。
所以…有没有人知道一个库或一段代码可以做到这一点,并且可能有更好的方式来表示差异(以一种仍然是JSON可序列化的方式)?
更新:
我想到了一个更好的方法来表示更新的数据,通过使用与newObj相同的对象结构,但将所有属性值转换为窗体上的对象:
{type: '<update|create|delete>', data: <propertyValue>}
如果newObj。prop1 = 'new value'和oldObj。prop1 = 'old value'它将设置returnbj。Prop1 = {type: 'update', data: 'new value'}
更新2:
当我们处理数组的属性时,它会变得非常麻烦,因为数组[1,2,3]应该被计算为等于[2,3,1],这对于基于值的类型的数组(如string, int和bool)来说足够简单,但是当涉及到引用类型的数组(如对象和数组)时就很难处理了。
数组的示例应该是相等的:
[1,[{c: 1},2,3],{a:'hey'}] and [{a:'hey'},1,[3,{c: 1},2]]
不仅要检查这种类型的深度值相等相当复杂,而且要找出一种表示可能发生的变化的好方法。
var base = [
{"value": "01", "label": "Pendências"},
{"value": "02", "label": "Ambulatório"},
{"value": "03", "label": "Urgência"},
{"value": "04", "label": "Clínica Médica"},
{"value": "05", "label": "Revisão"},
{"value": "06", "label": "Imagens"},
];
var used = [
{"value": "01", "label": "Pendências"},
{"value": "02", "label": "Ambulatório"},
{"value": "03", "label": "Urgência"},
{"value": "04", "label": "Clínica Médica"},
];
function diff(obj1,obj2) {
var temp = JSON.stringify(obj2.map((x)=> x.value));
return obj1.filter((y)=> temp.indexOf(y.value)<0 && y);
}
var result = diff(base, used);
console.clear();
console.log('RESULTADO');
console.log(result);
codeped
下面是一个JavaScript库,可以用来查找两个JavaScript对象之间的差异:
Github URL:
https://github.com/cosmicanant/recursive-diff
npm捷的url:北京方位www.npmjs.犯下/ recursiff
递归-diff库可以在浏览器中使用,也可以在基于Node.js的服务器端应用程序中使用。对于浏览器,它可以使用如下:
<script type="text" src="https://unpkg.com/recursive-diff@latest/dist/recursive-diff.min.js"/>
<script type="text/javascript">
const ob1 = {a:1, b: [2,3]};
const ob2 = {a:2, b: [3,3,1]};
const delta = recursiveDiff.getDiff(ob1,ob2);
/* console.log(delta) will dump following data
[
{path: ['a'], op: 'update', val: 2}
{path: ['b', '0'], op: 'update',val: 3},
{path: ['b',2], op: 'add', val: 1 },
]
*/
const ob3 = recursiveDiff.applyDiff(ob1, delta); //expect ob3 is deep equal to ob2
</script>
而在一个基于node.js的应用程序中,它可以这样使用:
const diff = require('recursive-diff');
const ob1 = {a: 1}, ob2: {b:2};
const diff = diff.getDiff(ob1, ob2);
如今,有相当多的模块可用于此。我最近写了一个模块来做到这一点,因为我不满意我发现的大量不同的模块。它被称为odiff: https://github.com/Tixit/odiff。我还列出了一些最流行的模块,以及为什么它们不能在odiff的自述中被接受,如果odiff没有你想要的属性,你可以查看一下。这里有一个例子:
var a = [{a:1,b:2,c:3}, {x:1,y: 2, z:3}, {w:9,q:8,r:7}]
var b = [{a:1,b:2,c:3},{t:4,y:5,u:6},{x:1,y:'3',z:3},{t:9,y:9,u:9},{w:9,q:8,r:7}]
var diffs = odiff(a,b)
/* diffs now contains:
[{type: 'add', path:[], index: 2, vals: [{t:9,y:9,u:9}]},
{type: 'set', path:[1,'y'], val: '3'},
{type: 'add', path:[], index: 1, vals: [{t:4,y:5,u:6}]}
]
*/
下面的方法将创建一个只更改字段的新对象
const findDiff = (obj1, obj2) => {
const isNativeType1 = typeof obj1 !== "object";
const isNativeType2 = typeof obj2 !== "object";
if (isNativeType1 && isNativeType2) {
return obj1 === obj2 ? null : obj2;
}
if (isNativeType1 && !isNativeType2) {
return obj2;
}
if (!isNativeType1 && isNativeType2) {
return obj2;
}
const isArray1 = Array.isArray(obj1);
const isArray2 = Array.isArray(obj2);
if (isArray1 && isArray2) {
const firstLenght = obj1.length;
const secondLenght = obj2.length;
const hasSameLength = firstLenght === secondLenght;
if (!hasSameLength) return obj2;
let hasChange = false;
for (let index = 0; index < obj1.length; index += 1) {
const element1 = obj1[index];
const element2 = obj2[index];
const changed = findDiff(element1, element2);
if (changed) {
hasChange = true;
}
}
return hasChange ? obj2 : null;
}
if (isArray1 || isArray2) return obj2;
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
const hasSameKeys = keys1.length === keys2.length;
if (!hasSameKeys) {
const retObj = { ...obj2 };
for (let index = 0; index < keys1.length; index += 1) {
const key = keys1[index];
if (!keys2.includes(key)) {
retObj[key] = null;
// eslint-disable-next-line no-continue
continue;
}
delete retObj[key];
}
return retObj;
}
let hasChange = false;
const retObj = {};
for (let index = 0; index < keys1.length; index += 1) {
const key = keys1[index];
const element1 = obj1[key];
const element2 = obj2[key];
const changed = findDiff(element1, element2);
if (changed) {
hasChange = true;
}
if (changed) {
retObj[key] = changed;
}
}
return hasChange ? retObj : null;
};
console.log(
JSON.stringify(findDiff(
{
a: 1,
b: 2,
c: {
a: ['1', 'b', { a: 'b', c: false }, true],
},
},
{
a: 1,
b: 2,
c: {
a: ['1','b', { a: 'b', c: true }, true],
},
}
), null, 2)
);