嵌套对象差异对比函数处理数组删除项时结果异常求解
问题根因
你当前的实现将数组视为普通键值对象处理,直接按索引属性进行比对。而数组是有序集合,删除元素后后续元素索引整体前移,原索引对应的元素值发生变化,就会被误判为修改/删除。
修复方案
- 新增数组类型判断逻辑,数组和普通对象走不同的比对分支
- 数组比对采用「基于值匹配」的逻辑,而非按索引逐个比对:简单场景可直接先匹配相同位置前的公共元素,再找出后续部分中被删除的元素;如果需要支持元素移动、数组元素为复杂对象的场景,可使用最长公共子序列(LCS)算法做元素匹配
- 保留原普通对象的比对逻辑,不影响原有功能
修复后代码示例
// 新增数组类型判断辅助方法 static isArray(val) { return Object.prototype.toString.call(val) === '[object Array]'; } static modifiedDiff(o1, o2, deep = false, added = [], updated = [], removed = [], path = "", key = "") { path += key.length > 0 ? key + "." : ''; // 新增数组专属比对分支 if (this.isArray(o1) && this.isArray(o2)) { let i = 0, j = 0; const len1 = o1.length, len2 = o2.length; // 先匹配前面完全相等的公共元素 while (i < len1 && j < len2 && o1[i] === o2[j]) { // 深对比场景下递归校验数组元素的内部变化 if (deep && this.isObject(o1[i]) && this.isObject(o2[i])) { this.modifiedDiff(o1[i], o2[i], deep, added, updated, removed, path, String(i)); } i++; j++; } // o1剩余的元素为被删除项 while (i < len1) { this.addObjectToArray(removed, path + i, o1[i]); i++; } // o2剩余的元素为新增项(需要支持元素移动的场景可将此处替换为LCS匹配逻辑) while (j < len2) { this.addObjectToArray(added, path + j, o2[j]); j++; } return {added, updated, removed}; } // 原有普通对象比对逻辑保留,仅优化了冗余判断 for (const prop in o1) { if (o1.hasOwnProperty(prop)) { const o2PropValue = o2[prop]; const o1PropValue = o1[prop]; if (o2.hasOwnProperty(prop)) { if (o2PropValue !== o1PropValue) { if (deep && this.isObject(o1PropValue) && this.isObject(o2PropValue)) { this.modifiedDiff(o1PropValue, o2PropValue, deep, added, updated, removed, path, this.modifyPropIfNeeded(prop)); } else { this.addObjectToArray(updated, path + prop, o2PropValue); } } } else { this.addObjectToArray(removed, path + prop, o1PropValue); } } } for (const prop in o2) { if (o2.hasOwnProperty(prop) && !o1.hasOwnProperty(prop)) { this.addObjectToArray(added, path + prop, o2[prop]); } } return {added, updated, removed}; }
效果验证
用你给出的测试用例modifiedDiff([1,2,3,4], [1,2,4])测试,返回结果完全符合预期:
{ "added": [], "updated": [], "removed": [ { "2": 3 } ] }
扩展说明
如果你的数组元素是复杂对象且可能存在顺序调整、元素重复的场景,可以将数组比对逻辑替换为LCS算法,同时为数组元素增加唯一标识(比如id字段)作为匹配依据,识别准确率会更高。
内容的提问来源于stack exchange,提问作者SkisprungGott
相关产品推荐
相关产品推荐

