首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >获取两个json对象的差异

获取两个json对象的差异
EN

Stack Overflow用户
提问于 2011-12-08 21:22:34
回答 5查看 88.8K关注 0票数 42

场景:我想要一个比较两个JSON对象的函数,并返回一个JSON对象,其中包含差异列表,如果可能,还会返回更多数据,比如覆盖率指标。

代码语言:javascript
复制
var madrid = '{"type":"team","description":"Good","trophies":[{"ucl":"10"}, {"copa":"5"}]}';
var barca = '{"type":"team","description":"Bad","trophies":[{"ucl":"3"}]}';

如果我运行compare(madrid, barca),返回的对象可能如下所示:

代码语言:javascript
复制
{"description" : "Bad", "trophies":[{"ucl":"3"}, {"copa":"5"}]}; 

或者类似的东西,你就明白了。

有没有人知道解决这个问题的办法?我已经找到了一个plugin,但我想知道是否有其他选择。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2011-12-08 22:06:32

可以使用通过对象键迭代的递归函数。然后使用Object.is测试NaNnull。然后测试第二个对象是否是像0NaNnull那样强制转换为false的类型。列出两个对象的键并将它们连接起来,以测试obj1中缺少的键,然后迭代它。

当相同的键值之间存在差异时,它存储object2的值并继续。如果两个键值都是object,这意味着可以递归比较,所以它确实是这样做的。

代码语言:javascript
复制
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/

一个重要的观察结果是,这会将数组转换为对象,并比较相同索引位置的值。由于所需的额外复杂性,还有许多其他方法来比较此函数未涵盖的数组。

EDIT 2/15/2019:此答案已更改,以添加新的ES2017语法并修复注释中的用例。

这只是一个开始,我还没有测试过它,但我从一个过滤器或比较器函数开始,它是递归的,可以根据需要更改它以获得优先结果。

代码语言:javascript
复制
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;
}

测试:http://jsfiddle.net/gartz/Q3BtG/2/

票数 54
EN

Stack Overflow用户

发布于 2014-03-12 03:57:42

您可以使用rus-diff https://github.com/mirek/node-rus-diff来创建与MongoDB兼容的(重命名/取消设置/设置) diff:

代码语言:javascript
复制
// 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))

输出:

代码语言:javascript
复制
{ '$unset': { 'trophies.1': true },
  '$set': { description: 'Bad', 'trophies.0.ucl': '3' } }
票数 8
EN

Stack Overflow用户

发布于 2014-08-07 14:48:17

将我的更改回馈给Gabriel Gartz版本。此函数在严格模式下工作,并删除数组检查-将始终为false。它还从diff中删除空节点。

代码语言:javascript
复制
//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;
};
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8431651

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档