两个对象之间的通用深度差异

我有两个对象:oldObj和newObj。


数据oldObj用于填充表单,newObj是用户更改此表单中的数据并提交数据的结果。


两个对象都很深,即。它们具有对象或对象数组等属性 - 它们可以是n级深度,因此diff算法需要是递归的。


现在我需要不只是从弄清楚什么改变(如添加/更新/删除)oldObj来newObj,却怎么也最能代表它。


到目前为止,我的想法只是构建一个genericDeepDiffBetweenObjects方法,它将返回表单上的对象,{add:{...},upd:{...},del:{...}}但后来我想:其他人必须先需要它。


那么......有没有人知道一个库或一段代码可以做到这一点,并且可能有更好的方式来表示差异(以一种仍然是JSON可序列化的方式)?


更新:

我想到了一种更好的方式来表示更新的数据,使用相同的对象结构newObj,但将所有属性值转换为表单上的对象:


{type: '<update|create|delete>', data: <propertyValue>}

所以,如果newObj.prop1 = 'new value'和oldObj.prop1 = 'old value'它会设置returnObj.prop1 = {type: 'update', data: 'new value'}


更新2:

当我们得到数组的属性时,它会变得非常毛茸茸,因为数组[1,2,3]应该被计算为等于[2,3,1],这对于基于值的类型的数组(如string,int和bool)来说非常简单,但是当涉及到它时,它实际上很难处理引用类型的数组,如对象和数组。


应该找到的示例数组相等:


[1,[{c: 1},2,3],{a:'hey'}] and [{a:'hey'},1,[3,{c: 1},2]]

检查这种类型的深度值相等不仅非常复杂,而且还要找出一种表示可能的变化的好方法。


米琪卡哇伊
浏览 549回答 3
3回答

慕少森

我写了一个做你想做的小课,你可以在这里测试一下。只有与你的提议不同的是我不认为[1,[{c: 1},2,3],{a:'hey'}] and [{a:'hey'},1,[3,{c: 1},2]]是相同的,因为我认为如果元素的顺序不相同,则数组不相等。当然,如果需要,可以更改。此代码还可以进一步增强,以便将函数作为参数,用于根据传递的原始值以任意方式格式化diff对象(现在这个作业由“compareValues”方法完成)。var deepDiffMapper = function () {&nbsp; return {&nbsp; &nbsp; VALUE_CREATED: 'created',&nbsp; &nbsp; VALUE_UPDATED: 'updated',&nbsp; &nbsp; VALUE_DELETED: 'deleted',&nbsp; &nbsp; VALUE_UNCHANGED: 'unchanged',&nbsp; &nbsp; map: function(obj1, obj2) {&nbsp; &nbsp; &nbsp; if (this.isFunction(obj1) || this.isFunction(obj2)) {&nbsp; &nbsp; &nbsp; &nbsp; throw 'Invalid argument. Function given, object expected.';&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; if (this.isValue(obj1) || this.isValue(obj2)) {&nbsp; &nbsp; &nbsp; &nbsp; return {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type: this.compareValues(obj1, obj2),&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; data: obj1 === undefined ? obj2 : obj1&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; var diff = {};&nbsp; &nbsp; &nbsp; for (var key in obj1) {&nbsp; &nbsp; &nbsp; &nbsp; if (this.isFunction(obj1[key])) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; var value2 = undefined;&nbsp; &nbsp; &nbsp; &nbsp; if (obj2[key] !== undefined) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; value2 = obj2[key];&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; diff[key] = this.map(obj1[key], value2);&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; for (var key in obj2) {&nbsp; &nbsp; &nbsp; &nbsp; if (this.isFunction(obj2[key]) || diff[key] !== undefined) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; continue;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; diff[key] = this.map(undefined, obj2[key]);&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; return diff;&nbsp; &nbsp; },&nbsp; &nbsp; compareValues: function (value1, value2) {&nbsp; &nbsp; &nbsp; if (value1 === value2) {&nbsp; &nbsp; &nbsp; &nbsp; return this.VALUE_UNCHANGED;&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; if (this.isDate(value1) && this.isDate(value2) && value1.getTime() === value2.getTime()) {&nbsp; &nbsp; &nbsp; &nbsp; return this.VALUE_UNCHANGED;&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; if (value1 === undefined) {&nbsp; &nbsp; &nbsp; &nbsp; return this.VALUE_CREATED;&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; if (value2 === undefined) {&nbsp; &nbsp; &nbsp; &nbsp; return this.VALUE_DELETED;&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; return this.VALUE_UPDATED;&nbsp; &nbsp; },&nbsp; &nbsp; isFunction: function (x) {&nbsp; &nbsp; &nbsp; return Object.prototype.toString.call(x) === '[object Function]';&nbsp; &nbsp; },&nbsp; &nbsp; isArray: function (x) {&nbsp; &nbsp; &nbsp; return Object.prototype.toString.call(x) === '[object Array]';&nbsp; &nbsp; },&nbsp; &nbsp; isDate: function (x) {&nbsp; &nbsp; &nbsp; return Object.prototype.toString.call(x) === '[object Date]';&nbsp; &nbsp; },&nbsp; &nbsp; isObject: function (x) {&nbsp; &nbsp; &nbsp; return Object.prototype.toString.call(x) === '[object Object]';&nbsp; &nbsp; },&nbsp; &nbsp; isValue: function (x) {&nbsp; &nbsp; &nbsp; return !this.isObject(x) && !this.isArray(x);&nbsp; &nbsp; }&nbsp; }}();var result = deepDiffMapper.map({&nbsp; a: 'i am unchanged',&nbsp; b: 'i am deleted',&nbsp; e: {&nbsp; &nbsp; a: 1,&nbsp; &nbsp; b: false,&nbsp; &nbsp; c: null&nbsp; },&nbsp; f: [1, {&nbsp; &nbsp; a: 'same',&nbsp; &nbsp; b: [{&nbsp; &nbsp; &nbsp; a: 'same'&nbsp; &nbsp; }, {&nbsp; &nbsp; &nbsp; d: 'delete'&nbsp; &nbsp; }]&nbsp; }],&nbsp; g: new Date('2017.11.25')}, {&nbsp; a: 'i am unchanged',&nbsp; c: 'i am created',&nbsp; e: {&nbsp; &nbsp; a: '1',&nbsp; &nbsp; b: '',&nbsp; &nbsp; d: 'created'&nbsp; },&nbsp; f: [{&nbsp; &nbsp; a: 'same',&nbsp; &nbsp; b: [{&nbsp; &nbsp; &nbsp; a: 'same'&nbsp; &nbsp; }, {&nbsp; &nbsp; &nbsp; c: 'create'&nbsp; &nbsp; }]&nbsp; }, 1],&nbsp; g: new Date('2017.11.25')});console.log(result);
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript