浅比较(也叫做引用比较),在js中 === 进行的比较就是浅比较,如果左右两边对象是是同一个对象的引用,则返回 true.
一般来说,深浅比较的区别在于对复杂类型的处理:
- 浅比较:
- 基本类型会比较值是否相等,复杂类型会比较引用地址是否相等
- 深比较:
- 递归遍历里层的每一个属性值是否相等(比较原值相是否等,不关注是否是同一引用)
在实现之前,先来看看下面这段代码中,对象的引用对于结果的影响:
console.log({a:1} === {a:1}) // false
const obj1 = {a:1};
const obj2 = obj1;
console.log(obj1 === obj2) //true
const child = {
x:1
}
const obj1 = {
a: 1,
b: child,
arr:[100,200,300]
}
const obj2 = {
a: 1,
b: child,
arr:[100,200,300]
}
console.log(obj1 === obj2) // false
console.log(obj1.a === obj2.a) // true
console.log(obj1.b === obj2.b) // true
console.log(obj1.arr === obj2.arr) // false
运行结果:
实现浅比较
因为深浅比较主要是对对象结构进行比较,所以需要除了非空校验,还要先判断数据类型(如果函数也归为对象,可以使用正则进行匹配)
判断是否是对象:
const isObj = function isObj(obj){
// return obj !== null && typeof obj === 'object'
return obj !== null && /^(object|function)$/.test(typeof obj) // 把函数也归为对象
}
浅比较实现:
- 判断数据是否是对象
- 获取两个对象的所有 key,使用Reflect.ownKeys()
- Object.keys(): 返回属性数组,不包括不可枚举的属性
- Reflect.ownKeys():包括不可枚举的属性Object.getOwnPropertyNames(target).concat(Object.getOwnPropertySymbols(target)
- 判断上一步生成的两个key值数组的长度,如果相等进行下一步
- 进行浅比较(只比较一层)
- 如果某个key值只存在于其中一个数组中,false
- 如果两个对象中 key 相同,值不同,false
代码实现:
const shallowEqual = function shallowEqual(obj1,obj2){
if(!isObj(obj1) || !isObj(obj2)) return false // 不是对象
let keys1 = Reflect.ownKeys(obj1)
let keys2 = Reflect.ownKeys(obj2)
if(keys1.length !== keys2.length) return false // 两个对象长度不同,不相等
// 浅比较
for(let i=0;i<keys1.length;i++) {
let key = keys1[i]
if(!obj2.hasOwnProperty(key) || obj1[key] !== obj2[key]) return false
}
return true
}