
本文介绍一种轻量、高性能的递归算法,用于快速计算两个对象的深层差异,自动标识新增、修改和已删除的属性(删除项值为 "deleted"),适用于高频调用场景。
本文介绍一种轻量、高性能的递归算法,用于快速计算两个对象的深层差异,自动标识新增、修改和已删除的属性(删除项值为 `"deleted"`),适用于高频调用场景。
在前端性能敏感的应用(如实时状态同步、表单变更追踪、JSON Patch 生成)中,频繁对比两个嵌套对象的差异需兼顾准确性和执行效率。Object.is() 语义一致、无依赖、零序列化开销的纯函数式实现,是比 JSON.stringify 或第三方库(如 deep-diff、lodash.isEqual 配合手动遍历)更优的选择。
以下是一个经过优化的差异计算函数,支持任意深度的对象嵌套,并严格区分新增、修改与删除:
const diff = (oldObj, newObj, result = {}) => {
// 处理 newObj 中的键:新增或修改
for (const key in newObj) {
if (!Object.prototype.hasOwnProperty.call(newObj, key)) continue;
const oldValue = oldObj?.[key];
const newValue = newObj[key];
// 值相同(含 null/undefined/NaN 安全比较)
if (Object.is(oldValue, newValue)) continue;
// 若均为普通对象(非 Array、Date、RegExp 等),递归深入
if (
oldValue !== null &&
newValue !== null &&
typeof oldValue === 'object' &&
typeof newValue === 'object' &&
oldValue.constructor === Object &&
newValue.constructor === Object
) {
result[key] = {};
diff(oldValue, newValue, result[key]);
} else {
result[key] = newValue;
}
}
// 处理 oldObj 中存在但 newObj 中缺失的键 → 标记为 "deleted"
for (const key in oldObj) {
if (
Object.prototype.hasOwnProperty.call(oldObj, key) &&
!Object.prototype.hasOwnProperty.call(newObj, key)
) {
result[key] = 'deleted';
}
}
return result;
};✅ 使用示例:
const obj1 = { a: "hi", b: "hi", c: { o: "hi", p: "hi" }, d: ["hi", "bye"] };
const obj2 = { a: "hi", b: "bye", c: { o: "bye" }, e: "new" };
console.log(diff(obj1, obj2));
// 输出:{ b: "bye", c: { o: "bye", p: "deleted" }, d: "deleted", e: "new" }⚠️ 关键注意事项:
立即学习“Java免费学习笔记(深入)”;
- 不处理数组差异:当前实现将整个数组视为原子值(若 obj1.d !== obj2.d,则 d: "deleted" 或 d: [...])。如需细粒度数组 diff(如增删项、移动),需额外集成 diff-match-patch 或自定义索引比对逻辑。
- 类型安全限制:仅递归进入 constructor === Object 的纯对象,避免误入 Date、Map、class 实例等;若需扩展,可添加 Array.isArray() 分支并实现元素级比对。
- 性能提示:该函数时间复杂度为 O(n),其中 n 是两个对象键的总数;避免在循环中传入超深或超大对象;生产环境建议配合 Object.freeze() 输入参数防止意外修改。
- 不可枚举属性:仅遍历自有可枚举属性(通过 hasOwnProperty + for...in),符合常规 JSON 序列化行为;若需处理 Symbol 键或不可枚举属性,需补充 Object.getOwnPropertySymbols() 和 Object.getOwnPropertyNames()。
该方案以最小依赖、最大可控性满足“高频、精准、低开销”的核心诉求,可直接集成至状态管理中间件或 DevTools 变更调试器中。










