对象的比较方法

一、前言

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

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

相关推荐
也无晴也无风雨24 分钟前
深入剖析输入URL按下回车,浏览器做了什么
前端·后端·计算机网络
Martin -Tang1 小时前
Vue 3 中,ref 和 reactive的区别
前端·javascript·vue.js
FakeOccupational2 小时前
nodejs 020: React语法规则 props和state
前端·javascript·react.js
放逐者-保持本心,方可放逐3 小时前
react 组件应用
开发语言·前端·javascript·react.js·前端框架
曹天骄4 小时前
next中服务端组件共享接口数据
前端·javascript·react.js
阮少年、4 小时前
java后台生成模拟聊天截图并返回给前端
java·开发语言·前端
郝晨妤5 小时前
鸿蒙ArkTS和TS有什么区别?
前端·javascript·typescript·鸿蒙
AvatarGiser6 小时前
《ElementPlus 与 ElementUI 差异集合》Icon 图标 More 差异说明
前端·vue.js·elementui
喝旺仔la6 小时前
vue的样式知识点
前端·javascript·vue.js
别忘了微笑_cuicui6 小时前
elementUI中2个日期组件实现开始时间、结束时间(禁用日期面板、控制开始时间不能超过结束时间的时分秒)实现方案
前端·javascript·elementui