我希望能够获得两个JavaScript对象图之间所有差异的列表,以及发生增量的属性名称和值。
对于它的价值,这些对象通常作为JSON从服务器中检索,并且通常只有少数深层(即它可能是一个对象数组,它们本身拥有数据,然后是带有其他数据对象的数组) )。
我不仅希望看到对基本属性的更改,还要查看数组成员数量的差异等。
如果我没有得到答案,我可能最终会自己写这篇文章,但希望有人已经完成了这项工作,或者知道某人的工作。
编辑:这些物体通常在结构上彼此非常接近,所以我们不是在讨论彼此完全不同的物体,而是可能有3或4个增量。
答案 0 :(得分:19)
这是我的问题的一个部分,天真的解决方案 - 我会在进一步开发时更新它。
function findDifferences(objectA, objectB) {
var propertyChanges = [];
var objectGraphPath = ["this"];
(function(a, b) {
if(a.constructor == Array) {
// BIG assumptions here: That both arrays are same length, that
// the members of those arrays are _essentially_ the same, and
// that those array members are in the same order...
for(var i = 0; i < a.length; i++) {
objectGraphPath.push("[" + i.toString() + "]");
arguments.callee(a[i], b[i]);
objectGraphPath.pop();
}
} else if(a.constructor == Object || (a.constructor != Number &&
a.constructor != String && a.constructor != Date &&
a.constructor != RegExp && a.constructor != Function &&
a.constructor != Boolean)) {
// we can safely assume that the objects have the
// same property lists, else why compare them?
for(var property in a) {
objectGraphPath.push(("." + property));
if(a[property].constructor != Function) {
arguments.callee(a[property], b[property]);
}
objectGraphPath.pop();
}
} else if(a.constructor != Function) { // filter out functions
if(a != b) {
propertyChanges.push({ "Property": objectGraphPath.join(""), "ObjectA": a, "ObjectB": b });
}
}
})(objectA, objectB);
return propertyChanges;
}
以下是一个如何使用它以及它将提供的数据的示例(请原谅长长的例子,但我想使用相对不重要的东西):
var person1 = {
FirstName : "John",
LastName : "Doh",
Age : 30,
EMailAddresses : [
"john.doe@gmail.com",
"jd@initials.com"
],
Children : [
{
FirstName : "Sara",
LastName : "Doe",
Age : 2
}, {
FirstName : "Beth",
LastName : "Doe",
Age : 5
}
]
};
var person2 = {
FirstName : "John",
LastName : "Doe",
Age : 33,
EMailAddresses : [
"john.doe@gmail.com",
"jdoe@hotmail.com"
],
Children : [
{
FirstName : "Sara",
LastName : "Doe",
Age : 3
}, {
FirstName : "Bethany",
LastName : "Doe",
Age : 5
}
]
};
var differences = findDifferences(person1, person2);
此时,如果将differences
数组序列化为JSON,这就是[
{
"Property":"this.LastName",
"ObjectA":"Doh",
"ObjectB":"Doe"
}, {
"Property":"this.Age",
"ObjectA":30,
"ObjectB":33
}, {
"Property":"this.EMailAddresses[1]",
"ObjectA":"jd@initials.com",
"ObjectB":"jdoe@hotmail.com"
}, {
"Property":"this.Children[0].Age",
"ObjectA":2,
"ObjectB":3
}, {
"Property":"this.Children[1].FirstName",
"ObjectA":"Beth",
"ObjectB":"Bethany"
}
]
数组的样子:
this
Property
值中的{{1}}指的是被比较对象的根。所以,这个解决方案还没有完全我需要的东西,但它非常接近。
希望这对那里的人有用,如果你有任何改进的建议,我全心全意;我昨晚很晚(即今天凌晨)写了这篇文章,可能还有一些我完全忽视的事情。
感谢。
答案 1 :(得分:15)
在查看现有答案后,我注意到https://github.com/flitbit/diff库尚未列为解决方案。
从我的研究来看,这个库在积极开发,贡献和分叉方面似乎是最好的,可以解决差异对象的挑战。这对于在服务器端创建diff并仅向客户端传递更改的位非常方便。
答案 2 :(得分:8)
有objectDiff library允许你这样做。在demo page上,您可以看到两个javascript对象之间存在差异。
答案 3 :(得分:5)
您还可以尝试生成兼容MongoDB(重命名/取消设置/设置)差异的rus-diff https://github.com/mirek/node-rus-diff。
对于您的示例对象:
var person1 = {
FirstName: "John",
LastName: "Doh",
Age: 30,
EMailAddresses: ["john.doe@gmail.com", "jd@initials.com"],
Children: [
{
FirstName: "Sara",
LastName: "Doe",
Age: 2
}, {
FirstName: "Beth",
LastName: "Doe",
Age: 5
}
]
};
var person2 = {
FirstName: "John",
LastName: "Doe",
Age: 33,
EMailAddresses: ["john.doe@gmail.com", "jdoe@hotmail.com"],
Children: [
{
FirstName: "Sara",
LastName: "Doe",
Age: 3
}, {
FirstName: "Bethany",
LastName: "Doe",
Age: 5
}
]
};
var rusDiff = require('rus-diff').rusDiff
console.log(rusDiff(person1, person2))
它生成一组集合:
{ '$set':
{ 'Age': 33,
'Children.0.Age': 3,
'Children.1.FirstName': 'Bethany',
'EMailAddresses.1': 'jdoe@hotmail.com',
'LastName': 'Doe' } }
答案 4 :(得分:4)
解决方案1
使用JSON.stringify(obj)获取要比较的对象的字符串表示形式。将字符串保存到文件中。使用任何diff查看器来比较文本文件。
注意:JSON.stringify将忽略指向函数定义的属性。
解决方案2
这可以通过一些修改来做你想要的,它是函数_.isEqual(http://documentcloud.github.com/underscore/)的修改版本。请随时建议任何修改!我写了它来弄清楚两个物体之间的第一个区别在哪里。
// Given two objects find the first key or value not matching, algorithm is a
// inspired by of _.isEqual.
function diffObjects(a, b) {
console.info("---> diffObjects", {"a": a, "b": b});
// Check object identity.
if (a === b) return true;
// Different types?
var atype = typeof(a), btype = typeof(b);
if (atype != btype) {
console.info("Type mismatch:", {"a": a, "b": b});
return false;
};
// Basic equality test (watch out for coercions).
if (a == b) return true;
// One is falsy and the other truthy.
if ((!a && b) || (a && !b)) {
console.info("One is falsy and the other truthy:", {"a": a, "b": b});
return false;
}
// Unwrap any wrapped objects.
if (a._chain) a = a._wrapped;
if (b._chain) b = b._wrapped;
// One of them implements an isEqual()?
if (a.isEqual) return a.isEqual(b);
// Check dates' integer values.
if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();
// Both are NaN?
if (_.isNaN(a) && _.isNaN(b)) {
console.info("Both are NaN?:", {"a": a, "b": b});
return false;
}
// Compare regular expressions.
if (_.isRegExp(a) && _.isRegExp(b))
return a.source === b.source &&
a.global === b.global &&
a.ignoreCase === b.ignoreCase &&
a.multiline === b.multiline;
// If a is not an object by this point, we can't handle it.
if (atype !== 'object') {
console.info("a is not an object:", {"a": a});
return false;
}
// Check for different array lengths before comparing contents.
if (a.length && (a.length !== b.length)) {
console.info("Arrays are of different length:", {"a": a, "b": b});
return false;
}
// Nothing else worked, deep compare the contents.
var aKeys = _.keys(a), bKeys = _.keys(b);
// Different object sizes?
if (aKeys.length != bKeys.length) {
console.info("Different object sizes:", {"a": a, "b": b});
return false;
}
// Recursive comparison of contents.
for (var key in a) if (!(key in b) || !diffObjects(a[key], b[key])) return false;
return true;
};
答案 5 :(得分:3)
如果您使用的是NodeJS,此脚本也有NPM版本。 https://github.com/NV/objectDiff.js
飘柔。
答案 6 :(得分:1)
我最近写了一个模块来做这件事,因为我对我发现的众多差异模块并不满意(我列出了一些最流行的模块以及为什么它们在自述文件中不可接受)我的模块)。它被称为odiff
:https://github.com/Tixit/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}]}
]
*/
答案 7 :(得分:1)
<html>
<body>
<p id="source1"> </p>
<p id="source2"> </p>
<p id="source7"> DIFFERENCE TABLE</p>
<table border=''>
<thead>
<th>S.no</th>
<th>Name Of the Key</th>
<th>Object1 Value</th>
<th>Object2 Value</th>
</thead>
<tbody id="diff">
</tbody>
</table>
</body>
</html>
kubeadm init
答案 8 :(得分:0)
我找到的所有图书馆都不够,所以我写了自己的AngularJS工厂。它以两种方式比较对象,并仅返回相同结构中的差异。
/**
* Diff
* Original author: Danny Coulombe
* Creation date: 2016-05-18
*
* Work with objects to find their differences.
*/
controllers.factory('diff', [function() {
var factory = {
/**
* Compare the original object with the modified one and return their differences.
*
* @param original: Object
* @param modified: Object
*
* @return Object
*/
getDifferences: function(original, modified) {
var type = modified.constructor === Array ? [] : {};
var result = angular.copy(type);
var comparisons = [[original, modified, 1], [modified, original, 0]];
comparisons.forEach(function(comparison) {
angular.forEach(comparison[0], function(value, key) {
if(result[key] === undefined) {
if(comparison[1][key] !== undefined && value !== null && comparison[1][key] !== null && [Object, Array].indexOf(comparison[1][key].constructor) !== -1) {
result[key] = factory.getDifferences(value, comparison[1][key]);
}
else if(comparison[1][key] !== value) {
result[key] = comparison[comparison[2]][key];
}
if(angular.equals(type, result[key])
|| result[key] === undefined
|| (
comparison[0][key] !== undefined
&& result[key] !== null
&& comparison[0][key] !== null
&& comparison[0][key].length === comparison[1][key].length
&& result[key].length === 0
)) {
delete result[key];
}
}
});
});
return result;
}
};
return factory;
}]);
答案 9 :(得分:0)
您可以使用filter和indexOf
var first = [ 1, 2, 3, 4, 5 ];
var second = [ 4, 5, 6 ];
var difference = first.filter(x => second.indexOf(x) === -1);
console.log(difference);