JavaScript中判断两个对象是否相同(所有属性的值是否都相同)
在JavaScript中,判断两个对象的所有属性是否相同(包括嵌套对象)需要深度比较(deep comparison)。以下是几种实现方法:
方法1:简易深度比较(不考虑循环引用、Symbol和特殊对象)
javascript
复制
下载
function deepEqual(obj1, obj2) {// 基本类型直接比较if (obj1 === obj2) return true;// 检查是否为对象且非nullif (typeof obj1 !== 'object' || obj1 === null ||typeof obj2 !== 'object' || obj2 === null) {return false;}// 比较构造函数类型if (obj1.constructor !== obj2.constructor) return false;// 获取对象的键(仅自身可枚举属性)const keys1 = Object.keys(obj1);const keys2 = Object.keys(obj2);// 键数量不同则不等if (keys1.length !== keys2.length) return false;// 递归比较每个键的值for (const key of keys1) {if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) {return false;}}return true; }
方法2:完整深度比较(支持循环引用、Symbol和特殊对象)
javascript
复制
下载
function deepEqual(obj1, obj2, visited = new WeakMap()) {// 基本类型直接比较if (obj1 === obj2) return true;// 检查是否为对象且非nullif (typeof obj1 !== 'object' || obj1 === null ||typeof obj2 !== 'object' || obj2 === null) {return false;}// 处理循环引用if (visited.has(obj1) {return visited.get(obj1) === obj2;}visited.set(obj1, obj2);// 比较构造函数类型if (obj1.constructor !== obj2.constructor) return false;// 特殊对象处理if (obj1 instanceof Date) return obj1.getTime() === obj2.getTime();if (obj1 instanceof RegExp) return obj1.toString() === obj2.toString();// 获取所有键(包括Symbol和自身可枚举属性)const keys1 = Reflect.ownKeys(obj1);const keys2 = Reflect.ownKeys(obj2);// 键数量不同则不等if (keys1.length !== keys2.length) return false;// 递归比较每个键的值for (const key of keys1) {if (!Reflect.has(obj2, key) ||!deepEqual(obj1[key], obj2[key], visited)) {return false;}}return true; }
关键点说明
-
深度递归:
-
逐层比较嵌套对象的属性值。
-
使用递归处理嵌套结构。
-
-
循环引用处理:
-
通过
WeakMap
记录已比较对象,避免无限递归。 -
当检测到循环引用时直接比较引用是否相同。
-
-
特殊对象支持:
-
Date:比较时间戳。
-
RegExp:比较正则表达式的字符串形式。
-
Array:自动支持(数组也是对象)。
-
-
键类型支持:
-
使用
Reflect.ownKeys()
获取所有自身键(包括Symbol)。 -
使用
Object.keys()
仅获取可枚举字符串键(简易版)。
-
-
严格检查:
-
比较构造函数确保类型一致(如
Array
vsObject
)。 -
键数量不等时快速失败。
-
使用示例
javascript
复制
下载
const objA = { a: 1, b: { c: 2 }, d: [3, 4] }; const objB = { a: 1, b: { c: 2 }, d: [3, 4] }; const objC = { a: 1, b: { c: 99 } };console.log(deepEqual(objA, objB)); // true console.log(deepEqual(objA, objC)); // false
注意事项
-
性能:深度比较可能较慢,避免在大型对象上使用。
-
特殊对象:如需支持
Set
/Map
等,需额外扩展。 -
函数属性:函数按引用比较(通常不比较函数体)。
-
库推荐:复杂场景建议使用 Lodash 的
_.isEqual()
。
javascript
复制
下载
// 使用 Lodash 的深度比较 import _ from 'lodash'; console.log(_.isEqual(objA, objB)); // true