You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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未实现)

但目前存在几个关键问题需要解决:

  1. 函数定义不完整,typeof v1 === "object"的分支未写完
  2. 未处理null(typeof null === 'object',会被误判为对象)
  3. this.EqualArr的调用存在上下文问题,every回调中的this默认不是函数本身
  4. 没有处理基本类型的直接比较
  5. 未考虑循环引用的情况,会导致无限递归栈溢出

完善后的完整实现

下面是补全并优化后的代码,解决了上述所有问题:

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:44:22