对象的比较方法

一、前言

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

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: 我是地霊殿__三無,希望能帮到你。

相关推荐
颜酱8 小时前
了解 pnpm 的优势,然后将已有项目的 yarn 换成 pnpm
前端·javascript·前端工程化
海在掘金611278 小时前
从"鬼知道这对象有啥"到"一目了然" - TS接口的实战魔力
前端
spionbo8 小时前
Vue 模拟键盘组件封装方法与使用技巧详解
前端
泉城老铁8 小时前
springboot 对接发送钉钉消息,消息内容带图片
前端·spring boot·后端
顾青8 小时前
微信小程序 VisionKit 实战(二):静态图片人脸检测与人像区域提取
前端·微信小程序
hmfy8 小时前
那些前端老鸟才知道的秘密
前端
野葳蕤8 小时前
react总览
前端
不一样的少年_8 小时前
她说想要浪漫,我把浏览器鼠标换成了柴犬,点一下就有烟花(附源码)
前端·javascript·浏览器
顾青8 小时前
微信小程序实现身份证识别与裁剪(基于 VisionKit)
前端·微信小程序
星链引擎8 小时前
技术深度聚焦版(侧重技术原理与代码细节)
前端