思路
- 实现两个对象的深度比较,模拟 lodash.isEqual() 写出一个简单的方案
- 地址不一样,属性一样,判定相等
要求
基于以下示例,来判定是否相等
// obj1 和 job2 完全一致
const obj1 = {a:10, b: {x: 100, y: 200}};
const obj2 = {a:10, b: {x: 100, y: 200}};console.log(isEqual(obj1, obj2))// true
isEqual() 实现
// 判断是否是对象或数组
function isObject(obj) {return obj && (typeof obj === 'object');
}// 全相等(深度)
function isEqual(obj1, obj2) {// 值类型(注意,参与 equal 的一般不会是函数)函数不考虑if (!isObject(obj1) || !isObject(obj2)) return obj1 === obj2;// 允许 obj1 === obj1的情况if (obj1 === obj2) return true;// 两个都是对象或数组,而且不相等// 1. 先取出 obj1 和 obj2 的 keys ,比较个数const obj1Keys = Object.keys(obj1);const obj2Keys = Object.keys(obj2);// 属性个数不同,不全等,包括数组if (obj1Keys.length !== obj2Keys.length) return false;// 2. 遍历来进行比较,记录最终的 boolean 变量let flag = true; // 默认为trueconst keys = Object.keys(obj1);keys.some((key) => {// 以 obj1 为基准,和 obj2 一次递归比较const flag = isEqual(obj1[key], obj2[key]);if (!flag) {flag = false;return true;}})// 3. 返回 flagreturn flag;
}
- 对于对象属性的处理,递归是一个非常好的方式
- 对属性的遍历 Object.keys 不会访问原型链上的属性
- 如需处理原型链上的东西,请使用 for - in 替代
- 一般而言,不需要处理原型链的对比, 这样会提升性能
代码测试
// 测试
const obj1 = { a: 100, b: {x: 100, y: 200 } };
const obj2 = { a: 100, b: {x: 100, y: 200 } };console.log( obj1 === obj2 ) // false
console.log( isEqual(obj1, obj2) ) // trueconst arr1 = [1, 2, 3, 4, [5, [6, 7]]];
const arr2 = [1, 2, 3, 4, [5, [6, 7]]];
console.log(arr1 === arr2); // false
console.log( isEqual(arr1, arr2) ) // true