一、前言
对象的比较是我们经常遇到的情况。本文来看看,对象之间应该如何比较呢?
1、例子
css
const a = {
num: '1'
}
const b = {
num: '1'
}
const result1 = (a === b)
const result2 = (a == b)
按我们的平时的逻辑,我们会认为变量a和b应该相同吧。
可现实是: result1的结果是false, 但也可以理解,因为===是严格比较,变量a和b是不同的实例变量,内存位置指向也不同,结果是false也正常。
那result2呢,结果为什么也是false。
因为平时我们比较对象,不会在意变量的内存地址是否相同, 而通过严格相等运算符===和宽松相等运算符==来进行对象比较,都是通过指针指向的内存地址来做比较的。
但是在平时我们的业务中,基本上只要两个对象的内容是一致的,或者说某个属性值(如id)相同,我们就会把两个对象认为是相同的。
这就引出了不同的比较方法。
二、比较方式
1、严格比较----判断是否同个实例
也就是上述的例子,严格相等运算符===和宽松相等运算符==。
Object.is()方法用来判断两个值是否严格相等。它与严格比较运算符(===)的行为基本一致。 Object.is()方法在以下情况会返回true。
- 两个值都是undefined。
- 两个值都是null。
- 两个值都是NaN。
- 两个值都是true或false。
- 两个值都是相同个数的字符并且按照相同顺序组成的字符串。
- 两个值都指向同一个对象。
- 两个值都是正零(+0)、都是负零(-0)和都是除零和NaN外的其他同一个数字。
css
用法:
Object.is(a, b);
2、仅比较某个属性值,手动实现
如果仅仅是比较某个值,可以封装成简单的函数,传入比较的对象和比较的属性名,即可简单返回布尔值。
python
function isEqual(object1, object2, str) {
return object1[str] === object2[str]
}
isEqual(a, b, 'num')
3、多属性比较时,浅层比较
想要比较两个对象内容是否一致,思路是要遍历对象的所有键名和键值是否都一致:
1、判断两个对象是否指向同一内存
2、使用Object.getOwnPropertyNames/Object.keys获取对象所有键名数组
3、判断两个对象的键名数组是否相等
4、遍历键名,判断键值是否都相等
4、多属性而且属性又嵌套对象后,深层递归比较
深层递归比较,其实跟浅层的逻辑差不多,不过就是增加了递归的逻辑。
不用for循环的原因,下面是示例的代码,对象属性的顺序也必须一致,才会返回相同。
所以我选择用for + hasOwnProperty的方式进行编码。
javascript
// 对比对象是否相同
export const isObjectValueEqual = (a, b) => {
// 判断两个对象是否指向同一内存,指向同一内存返回true
if (a === b) return true
// 获取两个对象键值数组
// const aProps = Object.getOwnPropertyNames(a)
// const bProps = Object.getOwnPropertyNames(b)
const aProps = Object.keys(a)
const bProps = Object.keys(b)
console.log(aProps, bProps)
// 判断两个对象键值数组长度是否一致,不一致返回false
if (aProps.length !== bProps.length) return false
// 遍历对象的键值
for (const prop in a) {
// 判断a的键值,在b中是否存在,不存在,返回false
if (b.hasOwnProperty(prop)) {
// 判断a的键值是否为对象,是则递归,不是对象直接判断键值是否相等,不相等返回false
if (typeof a[prop] === 'object') {
if (!isObjectValueEqual(a[prop], b[prop])) return false
} else if (a[prop] !== b[prop]) {
return false
}
} else {
return false
}
}
return true
}
注意Object.getOwnPropertyNames有坑。
特别是在vue项目中,父组件与子组件进行传递数据时,数据对象会多出一个属性__ob__: Observer,此属性是vue框架对数据设置的监控器,一般都是不可枚举的。而使用Object.getOwnPropertyNames(obj).forEach遍历对象去遍历父组件传来的对象时,会遍历出不可枚举对象,导致实际遍历结果数据量增多,此时,换成Objec.keys(obj).forEach()遍历就不会遍历到这个不可枚举属性;
正常我两个对象都是14个键名,
用object.keys遍历是14个
用object.getOwnPropertyNames遍历则多了一个,就是 ob 属性,多枚举了一个则导致了返回结果错误。
三、小结
上述方式也只是冰山一角,比较方式和实现方式还有很多,欢迎jym各显神通。
ps: 我是地霊殿__三無,希望能帮到你。