如何获得两个JavaScript对象图之间的差异列表?

问题描述 投票:16回答:9

我希望能够获得两个JavaScript对象图之间所有差异的列表,并带有出现变化的属性名称和值。

对于其价值而言,这些对象通常以JSON的形式从服务器中检索,并且通常不超过几层深度(即,它可能是一个本身具有数据的对象数组,然后是与其他数据对象组成的数组) 。

我不仅希望看到基本属性的更改,还希望看到数组成员数量的差异,等等。

如果我没有得到答案,我可能最终会自己写这个,但希望有人已经完成了这项工作或知道有人做了。


编辑:这些对象通常在结构上非常接近,因此我们不是在谈论彼此完全不同但可能具有3或4个增量的对象。

javascript json data-structures diff
9个回答
15
投票

查看现有答案后,我注意到https://github.com/flitbit/diff库尚未作为解决方案列出。

根据我的研究,从主动开发,贡献和解决分歧对象挑战的角度看,这个库似乎是最好的。这对于在服务器端创建差异并仅将更改的位传递给客户端非常方便。


20
投票

这里是我的问题的部分,幼稚的解决方案,我会在进一步开发时对其进行更新。

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 : [
      "[email protected]", 
      "[email protected]"
   ], 
   Children : [ 
      { 
         FirstName : "Sara", 
         LastName : "Doe", 
         Age : 2 
      }, { 
         FirstName : "Beth", 
         LastName : "Doe", 
         Age : 5 
      } 
   ] 
};

var person2 = { 
   FirstName : "John", 
   LastName : "Doe", 
   Age : 33, 
   EMailAddresses : [
      "[email protected]", 
      "[email protected]"
   ], 
   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":"[email protected]", 
      "ObjectB":"[email protected]"
   }, {
      "Property":"this.Children[0].Age", 
      "ObjectA":2, 
      "ObjectB":3
   }, {
      "Property":"this.Children[1].FirstName", 
      "ObjectA":"Beth", 
      "ObjectB":"Bethany"
   }
]

this值中的Property指的是被比较对象的根。因此,该解决方案还不是我所需要的,但是距离还很遥远。 希望这对外面的人很有用,如果您有任何改进的建议,我将全力以赴;我昨晚(即今天清晨)写了这篇文章,可能有些事情我完全忽略了。

谢谢。


8
投票
objectDiff library允许您执行此操作。在其demo page上,您可以看到两个javascript对象之间的区别。

5
投票
您也可以尝试rus-diff https://github.com/mirek/node-rus-diff,它会生成与MongoDB兼容的(重命名/未设置/设置)差异。

4
投票

解决方案1


3
投票
如果您使用的是NodeJS,此脚本也具有NPM版本。 https://github.com/NV/objectDiff.js

1
投票
我最近编写了一个模块来执行此操作,因为我对发现的众多差异模块不满意(我列出了一堆最受欢迎的模块,以及为什么在我的模块自述文件中不接受它们)。它称为odiffhttps://github.com/Tixit/odiff。这是一个例子:

1
投票

0
投票
我发现的库都不足够,所以我写了自己的AngularJS工厂。它以两种方式比较对象,并且仅返回同一结构内的差异。
© www.soinside.com 2019 - 2024. All rights reserved.