简体   繁体   English

使用递归函数进行对象比较

[英]Objects comparison with recursive function

Consider the following function's blueprint which tries to compare two objects: 考虑以下函数的蓝图,该蓝图试图比较两个对象:

function objectCompare(a,b,path){ 
    for (var prop in a) {
      path=prop;
      if (a.hasOwnProperty(prop) && !(b.hasOwnProperty(prop))) {
                ...
          return false;
      }
      ...
      if (detectType(a[prop])==='Object'){
          if (!objectCompare(a[prop],b[prop],path)) 
               return false;
      }
      ...
    }
      return true;
}

detectType is my own function which checks the type of a variable. detectType是我自己的函数,用于检查变量的类型。 My problem is that I want to enrich variable path every time we have a recursive call. 我的问题是,每次我们进行递归调用时,我都想丰富变量path However, at the same time when recursive calls finish, path has to traverse the remaining property names of the initial object without being enriched... Imagine the following objects: 但是,在递归调用完成的同时, path必须遍历初始对象的其余属性名称,而无需进行充实...想象以下对象:

var Obj1 = {
        p1: 's',
        p2: {
          p1: {a: { propA: 'a', propB: 'b' }},
          p2: 'g',
        }
      };

var Obj2 = {
        p1: 's',
        p2: {
          p1: {a: { propA: 'a', propB: 'c' }},
          p2: 'g',
        }
      };

I want path when function objectCompare returns to have the following value: p2.p1.a.propB Namely, the point which makes the two objects different. 我希望函数objectCompare返回时的path具有以下值: p2.p1.a.propB即,使两个对象不同的点。 How may I achieve that? 我该如何实现?

You have to add the current key to the path and pass the new path to the recursive call. 您必须将当前键添加到路径,并将新路径传递给递归调用。 Consider: 考虑:

 console.info=function(x){document.write('<pre>'+JSON.stringify(x,0,3)+'</pre>')} //-- // compare: return path if a,b are different, null otherwise function compare(a, b, path) { var ta = typeof a, tb = typeof b; // different types - fail if (ta !== tb) { return path; } // scalars - null if equal, path if not if (ta !== 'object') { return a === b ? null : path; } // make a set of keys from both objects var keys = Object.keys(a).concat(Object.keys(b)).filter(function(x, i, self) { return self.indexOf(x) === i; }); // for each key in set, compare values var res = null; keys.some(function(k) { return res = compare(a[k], b[k], path.concat(k)); }); // return null or the first failed path return res; } // var Obj1 = { p1: 's', p2: { p1: {a: { propA: 'a', propB: 'b' }}, p2: 'g', } }; var Obj2 = { p1: 's', p2: { p1: {a: { propA: 'a', propB: 'c' }}, p2: 'g', } }; var res = compare(Obj1, Obj2, []) console.info(res); 

The library deep-diff does what you need. deep-diffdeep-diff您的需求。

The above reference presents this example code: 上面的参考提供了以下示例代码:

var diff = require('deep-diff').diff;

var lhs = {
    name: 'my object',
    description: 'it\'s an object!',
    details: {
        it: 'has',
        an: 'array',
        with: ['a', 'few', 'elements']
    }
};

var rhs = {
    name: 'updated object',
    description: 'it\'s an object!',
    details: {
        it: 'has',
        an: 'array',
        with: ['a', 'few', 'more', 'elements', { than: 'before' }]
    }
};

var differences = diff(lhs, rhs);

The code snippet above would result in the following structure describing the differences: 上面的代码段将导致以下结构描述差异:

[ { kind: 'E',
    path: [ 'name' ],
    lhs: 'my object',
    rhs: 'updated object' },
  { kind: 'E',
    path: [ 'details', 'with', 2 ],
        lhs: 'elements',
        rhs: 'more' },
  { kind: 'A',
    path: [ 'details', 'with' ],
    index: 3,
    item: { kind: 'N', rhs: 'elements' } },
  { kind: 'A',
    path: [ 'details', 'with' ],
    index: 4,
    item: { kind: 'N', rhs: { than: 'before' } } } ]

Notably the path property is much like your desired output. 值得注意的是, path属性非常类似于您所需的输出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM