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
可能足夠。 - 對於更復雜的情況,遞迴方法提供更大的控制力和靈活性。
- 對於需要處理迴圈引用或其他邊緣情況的生產