场景:我想要一个比较两个JSON对象的函数,并返回一个带有差异列表的JSON对象,如果可能的话还会返回更多数据,例如覆盖率指标。
var madrid = '{"type":"team","description":"Good","trophies":[{"ucl":"10"}, {"copa":"5"}]}';
var barca = '{"type":"team","description":"Bad","trophies":[{"ucl":"3"}]}';
如果我运行compare(madrid, barca)
,则返回的对象可能类似于:
{"description" : "Bad", "trophies":[{"ucl":"3"}, {"copa":"5"}]};
或类似的东西,你明白了。
有谁知道这个解决方案?我已经找到了一个plugin,但我想知道是否有其他选择。
答案 0 :(得分:28)
可以使用通过对象键迭代的递归函数。然后使用Object.is来测试NaN
和null
。然后测试第二个对象是否是强制转换为false
的类型,例如0
,NaN
或null
。
列出两个对象的键并将它们连接起来以测试obj1
中缺少的键,然后迭代它。
当相同的键值之间存在差异时,它会存储object2
的值并继续。如果两个键值都是对象意味着可以递归地进行比较,那么它就是。
function diff(obj1, obj2) {
const result = {};
if (Object.is(obj1, obj2)) {
return undefined;
}
if (!obj2 || typeof obj2 !== 'object') {
return obj2;
}
Object.keys(obj1 || {}).concat(Object.keys(obj2 || {})).forEach(key => {
if(obj2[key] !== obj1[key] && !Object.is(obj1[key], obj2[key])) {
result[key] = obj2[key];
}
if(typeof obj2[key] === 'object' && typeof obj1[key] === 'object') {
const value = diff(obj1[key], obj2[key]);
if (value !== undefined) {
result[key] = value;
}
}
});
return result;
}
上面的代码是BSD许可的,可以在任何地方使用。
测试链接:https://jsfiddle.net/gartz/vy9zaof2/54/
一个重要的观察,这会将数组转换为对象并比较相同索引位置的值。由于需要额外的复杂性,还有许多其他方法可以比较此函数未涵盖的数组。
编辑2/15/2019:此答案已更改为添加新的ES2017语法并修复评论中的用例。
这只是一个启动,我还没有测试它,但我开始使用过滤器或比较器功能,这是递归的,但需要更改它,但需要获得优先结果。
function filter(obj1, obj2) {
var result = {};
for(key in obj1) {
if(obj2[key] != obj1[key]) result[key] = obj2[key];
if(typeof obj2[key] == 'array' && typeof obj1[key] == 'array')
result[key] = arguments.callee(obj1[key], obj2[key]);
if(typeof obj2[key] == 'object' && typeof obj1[key] == 'object')
result[key] = arguments.callee(obj1[key], obj2[key]);
}
return result;
}
答案 1 :(得分:6)
你可以使用创建MongoDB兼容(重命名/取消设置/设置)差异的rus-diff https://github.com/mirek/node-rus-diff:
// npm install rus-diff
var madrid = {"type":"team","description":"Good","trophies":[{"ucl":"10"}, {"copa":"5"}]};
var barca = {"type":"team","description":"Bad","trophies":[{"ucl":"3"}]};
var rusDiff = require('rus-diff').rusDiff
console.log(rusDiff(madrid, barca))
输出:
{ '$unset': { 'trophies.1': true },
'$set': { description: 'Bad', 'trophies.0.ucl': '3' } }
答案 2 :(得分:5)
回馈我对Gabriel Gartz版本的修改。这个工作在严格模式下并删除数组检查 - 将始终为false。它还从diff中删除空节点。
//http://stackoverflow.com/questions/679915/how-do-i-test-for-an-empty-javascript-object
var isEmptyObject = function(obj) {
var name;
for (name in obj) {
return false;
}
return true;
};
//http://stackoverflow.com/questions/8431651/getting-a-diff-of-two-json-objects
var diff = function(obj1, obj2) {
var result = {};
var change;
for (var key in obj1) {
if (typeof obj2[key] == 'object' && typeof obj1[key] == 'object') {
change = diff(obj1[key], obj2[key]);
if (isEmptyObject(change) === false) {
result[key] = change;
}
}
else if (obj2[key] != obj1[key]) {
result[key] = obj2[key];
}
}
return result;
};
答案 3 :(得分:0)
假设我们要比较两个相同的对象,并减去如果对象字段计数匹配,则遵循下面的代码。
var obj1 = {
"Agent": "12819",
"Beneficiary": "476949",
"BillingDetail": "13772",
"BillingInvoice": "914548",
"Claim": "1192",
"Customer": "656320",
"LifeAssured": "228493",
"Payment": "1091661",
"Policy/Proposal": "263196",
"Product": "9",
"ProductComponent": "53",
"ProductComponentOption": "2239791",
"ProductOption": "568785",
"TransactionDetail": "4289240"
}
var obj2 = {
"Agent": "1289",
"Beneficiary": "47694",
"BillingDetail": "13772",
"BillingInvoice": "914548",
"Claim": "1192",
"Customer": "656320",
"LifeAssured": "22893",
"Payment": "1091661",
"Policy/Proposal": "26316",
"Product": "2",
"ProductComponent": "52",
"ProductComponentOption": "223971",
"ProductOption": "56885",
"TransactionDetail": "4289240"
}
function diff(obj1, obj2) {
const result = {};
for(var o1 in obj1){
if(obj2[o1]){
result[o1] = obj1[o1] - obj2[o1];
}
}
return result;
}
console.log(diff(obj1,obj2))
结果:
{
"Agent": 11530,
"Beneficiary": 429255,
"BillingDetail": 0,
"BillingInvoice": 0,
"Claim": 0,
"Customer": 0,
"LifeAssured": 205600,
"Payment": 0,
"Policy/Proposal": 236880,
"Product": 7,
"ProductComponent": 1,
"ProductComponentOption": 2015820,
"ProductOption": 511900,
"TransactionDetail": 0
}
答案 4 :(得分:0)
我们可以使用JSON.Stringify
var obj1 = {
"Agent": "12819",
"Beneficiary": "476949",
"BillingDetail": "13772",
"BillingInvoice": "914548",
"Claim": "1192",
"Customer": "656320",
"LifeAssured": "228493",
"Payment": "1091661",
"Policy/Proposal": "263196",
"Product": "9",
"ProductComponent": "53",
"ProductComponentOption": "2239791",
"ProductOption": "568785",
"TransactionDetail": "4289240"
}
var obj2 = {
"Agent": "1289",
"Beneficiary": "47694",
"BillingDetail": "13772",
"BillingInvoice": "914548",
"Claim": "1192",
"Customer": "656320",
"LifeAssured": "22893",
"Payment": "1091661",
"Policy/Proposal": "26316",
"Product": "2",
"ProductComponent": "52",
"ProductComponentOption": "223971",
"ProductOption": "56885",
"TransactionDetail": "4289240"
}
JSON.stringify(obj1) == JSON.stringify(obj2)
false
var obj3 = {
"Agent": "1289",
"Beneficiary": "47694",
"BillingDetail": "13772",
"BillingInvoice": "914548",
"Claim": "1192",
"Customer": "656320",
"LifeAssured": "22893",
"Payment": "1091661",
"Policy/Proposal": "26316",
"Product": "2",
"ProductComponent": "52",
"ProductComponentOption": "223971",
"ProductOption": "56885",
"TransactionDetail": "4289240"
}
JSON.stringify(obj2) == JSON.stringify(obj3)
true