JavaScript对象深度比较函数实现:代码解析与技术咨询
完善JavaScript对象深度比较函数
Equal的实现 首先,先把你提供的未完成代码整理出来:
function Equal(obj1, obj2) { var keys1 = Object.keys(obj1).sort(); var keys2 = Object.keys(obj2).sort(); if (keys1.length !== keys2.length) { return false; } // first make sure have same keys. if (!keys1.every(function(k, i) { return (k === keys2[i]); })) { return false; } return keys1.every(function(kk) { var v1 = obj1[kk]; var v2 = obj2[kk]; if (Array.isArray(v1)) { return this.EqualArr(v1, v2); } else if (typeof v1 === "object...
现有逻辑分析
你的代码已经抓住了对象深度比较的核心步骤:
- 先通过
Object.keys获取键名,排序后比较数量和键名一致性,确保两个对象的键完全匹配 - 考虑到数组类型的子值,计划单独处理数组比较(虽然
EqualArr未实现)
但目前存在几个关键问题需要解决:
- 函数定义不完整,
typeof v1 === "object"的分支未写完 - 未处理
null(typeof null === 'object',会被误判为对象) this.EqualArr的调用存在上下文问题,every回调中的this默认不是函数本身- 没有处理基本类型的直接比较
- 未考虑循环引用的情况,会导致无限递归栈溢出
完善后的完整实现
下面是补全并优化后的代码,解决了上述所有问题:
function Equal(obj1, obj2, visited = new WeakMap()) { // 快速判断严格相等(包括基本类型、null、同一引用的对象/数组) if (obj1 === obj2) { return true; } // 处理其中一个为null/undefined,另一个不是的情况 if (obj1 == null || obj2 == null) { return false; } // 类型直接不一致,返回false if (typeof obj1 !== typeof obj2) { return false; } // 处理数组类型 if (Array.isArray(obj1)) { // 另一个不是数组或长度不一致,直接返回false if (!Array.isArray(obj2) || obj1.length !== obj2.length) { return false; } // 检查是否已访问过该数组,避免循环引用 if (visited.has(obj1)) { return visited.get(obj1) === obj2; } visited.set(obj1, obj2); // 递归比较数组每一项 return obj1.every((item, index) => Equal(item, obj2[index], visited)); } // 处理对象类型(排除数组和null) if (typeof obj1 === 'object') { const keys1 = Object.keys(obj1).sort(); const keys2 = Object.keys(obj2).sort(); // 键数量不一致直接返回false if (keys1.length !== keys2.length) { return false; } // 键名不完全匹配返回false if (!keys1.every((key, index) => key === keys2[index])) { return false; } // 检查是否已访问过该对象,避免循环引用 if (visited.has(obj1)) { return visited.get(obj1) === obj2; } visited.set(obj1, obj2); // 递归比较每个键对应的值 return keys1.every(key => Equal(obj1[key], obj2[key], visited)); } // 剩余基本类型,直接比较值 return obj1 === obj2; }
关键优化点说明
- 补充边界处理:新增了基本类型、
null/undefined的快速判断,避免无效递归 - 整合数组比较:把原计划的
EqualArr逻辑整合到函数内部,直接递归调用Equal,解决上下文问题 - 循环引用防护:使用
WeakMap记录已比较的对象/数组,防止无限递归,且WeakMap不会造成内存泄漏 - 类型校验增强:严格区分数组和普通对象,避免类型判断错误
测试案例
你可以用以下案例验证函数的正确性:
// 基本类型测试 console.log(Equal(1, 1)); // true console.log(Equal('test', 'test')); // true console.log(Equal(true, false)); // false // 简单对象测试 console.log(Equal({x: 1, y: 2}, {y: 2, x: 1})); // true console.log(Equal({x: 1}, {x: 2})); // false // 嵌套对象测试 console.log(Equal({a: {b: [3, 4]}}, {a: {b: [3, 4]}})); // true // 循环引用测试 const objX = {val: 5}; objX.self = objX; const objY = {val: 5}; objY.self = objY; console.log(Equal(objX, objY)); // true
内容的提问来源于stack exchange,提问作者simon
相关产品推荐
相关产品推荐

