js物件如何深比較?

王铁柱6發表於2024-12-02

JavaScript 物件的深比較幾種常見方法:

1. 使用 JSON.stringify:

這是最簡單的方法之一,但有一些限制。它將物件轉換為字串進行比較,因此無法處理迴圈引用,並且會忽略函式和 undefined 值。

function deepEqual(obj1, obj2) {
  return JSON.stringify(obj1) === JSON.stringify(obj2);
}

let obj1 = { a: 1, b: '2' };
let obj2 = { a: 1, b: '2' };
let obj3 = { b: '2', a: 1 }; // 即使屬性順序不同,也認為是相等的

console.log(deepEqual(obj1, obj2)); // true
console.log(deepEqual(obj1, obj3)); // true

let obj4 = { a: 1, b: 2 };
console.log(deepEqual(obj1, obj4)); // false

//  limitations
let obj5 = { a: 1, b: undefined };
let obj6 = { a: 1 };
console.log(deepEqual(obj5, obj6)); // false  undefined會被忽略

let obj7 = { a: function() {} };
let obj8 = { a: function() {} };
console.log(deepEqual(obj7, obj8)); // false 函式會被忽略

2. 遞迴比較:

這是更穩健的方法,可以處理各種資料型別,包括巢狀物件、陣列和函式。

function deepEqual(obj1, obj2) {
  if (typeof obj1 !== typeof obj2) return false;

  if (typeof obj1 === 'object') {
    if (Array.isArray(obj1)) {
      if (!Array.isArray(obj2) || obj1.length !== obj2.length) return false;
      for (let i = 0; i < obj1.length; i++) {
        if (!deepEqual(obj1[i], obj2[i])) return false;
      }
      return true;
    } else {
      const keys1 = Object.keys(obj1);
      const keys2 = Object.keys(obj2);
      if (keys1.length !== keys2.length) return false;
      for (const key of keys1) {
        if (!obj2.hasOwnProperty(key) || !deepEqual(obj1[key], obj2[key])) return false;
      }
      return true;
    }
  } else if (typeof obj1 === 'function') {
    //  比較函式通常比較複雜,可以比較函式的toString(),但並不完全可靠
    return obj1.toString() === obj2.toString();
  } else {
    return obj1 === obj2;
  }
}


let obj1 = { a: 1, b: { c: 3 } };
let obj2 = { a: 1, b: { c: 3 } };
console.log(deepEqual(obj1, obj2)); // true

let obj3 = { a: 1, b: { c: 4 } };
console.log(deepEqual(obj1, obj3)); // false

let arr1 = [1, 2, { a: 1 }];
let arr2 = [1, 2, { a: 1 }];
console.log(deepEqual(arr1, arr2)); // true

3. 使用 Lodash 的 _.isEqual:

Lodash 是一個流行的 JavaScript 實用工具庫,提供了一個 _.isEqual 函式,可以進行深度比較。它處理各種邊緣情況,包括迴圈引用。

const _ = require('lodash');

let obj1 = { a: 1, b: { c: 3 } };
let obj2 = { a: 1, b: { c: 3 } };
console.log(_.isEqual(obj1, obj2)); // true

let obj3 = { a: 1, b: { c: 4 } };
console.log(_.isEqual(obj1, obj3)); // false

// 處理迴圈引用
let obj4 = {};
obj4.a = obj4;
let obj5 = {};
obj5.a = obj5;
console.log(_.isEqual(obj4, obj5)); // true

選擇哪種方法?

  • 對於簡單的物件比較,JSON.stringify 可能足夠。
  • 對於更復雜的情況,遞迴方法提供更大的控制力和靈活性。
  • 對於需要處理迴圈引用或其他邊緣情況的生產

相關文章