获得两个json对象的差异

Sor*_*ami 26 javascript diff jquery json

场景:我想要一个比较两个JSON对象的函数,并返回一个带有差异列表的JSON对象,如果可能的话还有更多数据,例如覆盖度量.

var madrid = '{"type":"team","description":"Good","trophies":[{"ucl":"10"}, {"copa":"5"}]}';
var barca = '{"type":"team","description":"Bad","trophies":[{"ucl":"3"}]}';
Run Code Online (Sandbox Code Playgroud)

如果我运行compare(madrid, barca)返回的对象可能看起来像:

{"description" : "Bad", "trophies":[{"ucl":"3"}, {"copa":"5"}]}; 
Run Code Online (Sandbox Code Playgroud)

或类似的东西,你明白了.

有谁知道这个解决方案?我已经找到了一个插件,但我想知道是否还有其他选择.

Gab*_*rtz 35

可以使用通过对象键迭代的递归函数.然后使用Object.is来测试NaNnull.然后测试如果第二对象是强制转换为类型false喜欢0,NaNnull.列出两个对象的键并将它们连接起来测试其中的缺失键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;
}
Run Code Online (Sandbox Code Playgroud)

上面的代码是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;
}
Run Code Online (Sandbox Code Playgroud)

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

  • 我使用ES6更新了此示例,并删除了`argument.callee`语句(如果有人觉得有用):https://jsfiddle.net/thinkolson/n2jwv6mk/2/ (2认同)

Mir*_*sin 8

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

// 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))
Run Code Online (Sandbox Code Playgroud)

输出:

{ '$unset': { 'trophies.1': true },
  '$set': { description: 'Bad', 'trophies.0.ucl': '3' } }
Run Code Online (Sandbox Code Playgroud)


Leb*_*ses 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;
                };
Run Code Online (Sandbox Code Playgroud)