我有两个对象: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 o1 = {a: 1, b: 2, c: 2},
o2 = {a: 2, b: 1, c: 2};
_.omit(o1, function(v,k) { return o2[k] === v; })
o1中对应但o2值不同的部分的结果:
{a: 1, b: 2}
如果是深差的话就不一样了
function diff(a,b) {
var r = {};
_.each(a, function(v,k) {
if(b[k] === v) return;
// but what if it returns an empty object? still attach?
r[k] = _.isObject(v)
? _.diff(v, b[k])
: v
;
});
return r;
}
正如@Juhana在评论中指出的那样,上面只是一个diff a- >b,并且不可逆(这意味着b中的额外属性将被忽略)。用a——>b——>a代替:
(function(_) {
function deepDiff(a, b, r) {
_.each(a, function(v, k) {
// already checked this or equal...
if (r.hasOwnProperty(k) || b[k] === v) return;
// but what if it returns an empty object? still attach?
r[k] = _.isObject(v) ? _.diff(v, b[k]) : v;
});
}
/* the function */
_.mixin({
diff: function(a, b) {
var r = {};
deepDiff(a, b, r);
deepDiff(b, a, r);
return r;
}
});
})(_.noConflict());
完整的示例+tests+mixins请参见http://jsfiddle.net/drzaus/9g5qoxwj/
const diff = require("deep-object-diff").diff;
let differences = diff(obj2, obj1);
有一个每周下载量超过50万的npm模块:https://www.npmjs.com/package/deep-object-diff
我喜欢对象式的差异表示-特别是当它形成时,很容易看到结构。
const diff = require("deep-object-diff").diff;
const lhs = {
foo: {
bar: {
a: ['a', 'b'],
b: 2,
c: ['x', 'y'],
e: 100 // deleted
}
},
buzz: 'world'
};
const rhs = {
foo: {
bar: {
a: ['a'], // index 1 ('b') deleted
b: 2, // unchanged
c: ['x', 'y', 'z'], // 'z' added
d: 'Hello, world!' // added
}
},
buzz: 'fizz' // updated
};
console.log(diff(lhs, rhs)); // =>
/*
{
foo: {
bar: {
a: {
'1': undefined
},
c: {
'2': 'z'
},
d: 'Hello, world!',
e: undefined
}
},
buzz: 'fizz'
}
*/
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
使用下划线,一个简单的差异:
var o1 = {a: 1, b: 2, c: 2},
o2 = {a: 2, b: 1, c: 2};
_.omit(o1, function(v,k) { return o2[k] === v; })
o1中对应但o2值不同的部分的结果:
{a: 1, b: 2}
如果是深差的话就不一样了
function diff(a,b) {
var r = {};
_.each(a, function(v,k) {
if(b[k] === v) return;
// but what if it returns an empty object? still attach?
r[k] = _.isObject(v)
? _.diff(v, b[k])
: v
;
});
return r;
}
正如@Juhana在评论中指出的那样,上面只是一个diff a- >b,并且不可逆(这意味着b中的额外属性将被忽略)。用a——>b——>a代替:
(function(_) {
function deepDiff(a, b, r) {
_.each(a, function(v, k) {
// already checked this or equal...
if (r.hasOwnProperty(k) || b[k] === v) return;
// but what if it returns an empty object? still attach?
r[k] = _.isObject(v) ? _.diff(v, b[k]) : v;
});
}
/* the function */
_.mixin({
diff: function(a, b) {
var r = {};
deepDiff(a, b, r);
deepDiff(b, a, r);
return r;
}
});
})(_.noConflict());
完整的示例+tests+mixins请参见http://jsfiddle.net/drzaus/9g5qoxwj/