对象的比较方法

一、前言

对象的比较是我们经常遇到的情况。本文来看看,对象之间应该如何比较呢?

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。

  1. 两个值都是undefined。
  2. 两个值都是null。
  3. 两个值都是NaN。
  4. 两个值都是true或false。
  5. 两个值都是相同个数的字符并且按照相同顺序组成的字符串。
  6. 两个值都指向同一个对象。
  7. 两个值都是正零(+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: 我是地霊殿__三無,希望能帮到你。

相关推荐
VcB之殇1 小时前
popstate监听浏览器的前进后退事件
前端·javascript·vue.js
宁雨桥1 小时前
Vue组件初始化时序与异步资源加载的竞态问题实战解析
前端·javascript·vue.js
JIngJaneIL2 小时前
基于java+ vue家庭理财管理系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot
GISer_Jing2 小时前
Taro跨端开发实战:JX首页实现_Trae SOLO构建
前端·javascript·aigc·taro
vipbic2 小时前
基于 Nuxt 4 + Strapi 5 构建高性能 AI 导航站
前端·后端
不要em0啦2 小时前
从0开始学python:简单的练习题3
开发语言·前端·python
老华带你飞2 小时前
电商系统|基于java + vue电商系统(源码+数据库+文档)
java·开发语言·前端·数据库·vue.js·spring boot·后端
大猫会长3 小时前
关于http状态码4xx与5xx的背锅问题
前端
喝拿铁写前端3 小时前
AI 驱动前端开发覆盖的能力全景拆解
前端·javascript·人工智能
1024小神3 小时前
确认了,Cloudflare的R2对象存储S3接口api不支持在web端使用
前端