Skip to content

判断两个对象是否相等

我们一般认为两个对象有相同的属性并且值都一样,那他们就是相等的。但是js并不能直接用===判断对象是否相等

js
console.log({a: 1} === {a: 1})  // false
console.log([1, 2] === [1, 2])  // false

因为===判断的是内存地址是否相同,所以上面的对象和数组,虽然数据都是一样的但是对象的内存地址不一样,比较的话就为false

js
const a = {a: 1}
const b = a
console.log(a === b)  // true
console.log(Object.is(a, b))  // true

如果两个对象都指向同一个对象,他们地址相同,这样用===判断就会为true

shallowEqual

浅检测,只能检测对象里面都是普通类型的情况

js
// 浅检测
const shallowEqual = (obj1, obj2) => {
  if (Object.is(obj1, obj2)) {
    return true
  }
  if (typeof obj1 !== 'object' || Object.is(obj1, null) || typeof obj2 !== 'object' || Object.is(obj2, null)) {
    return false
  }

  const map1 = new Map(Object.entries(obj1))
  const map2 = new Map(Object.entries(obj2))
  if (map1.size !== map2.size) {
    return false
  }

  for (const [key, value] of map1) {
    if (!map2.has(key) || value !== map2.get(key)) {
      return false
    }
  }
  return true
}

const a = {a: 1}
const b = {a: 1}
console.log(shallowEqual(a, b))

deepEqual

深度检测对象是否相同,遇到对象类型的属性时会递归调用来判断。还有很多边界情况没有处理,比如不能判断两个map是否相同

js
const deepEqual = (obj1, obj2) => {
    // 如果两个对象内存地址相同它们就肯定是同一个对象
    if (Object.is(obj1, obj2)) {
        return true
    }
    // 如果obj不是对象或者是null返回false
    if (typeof obj1 !== 'object' || Object.is(obj1, null) || typeof obj2 !== 'object' || Object.is(obj2, null)) {
        return false
    }

    // 到这一步可以保证obj一定是对象类型,可能是object也可能是array
    // 转成map方便遍历
    const map1 = new Map(Object.entries(obj1))
    const map2 = new Map(Object.entries(obj2))
    // map长度不同对象肯定不同
    if (map1.size !== map2.size) {
        return false
    }
    // 遍历map1获取键值对数据
    for (const [key, value] of map1) {
      if (map2.has(key)) {
        const value2 = map2.get(key)
        // 如果当前值是object类型,就要递归调用,验证object是否相同
        if (value !== null && typeof value === 'object' && value2 !== null && typeof value2 === 'object') {
          // 因为shallowEqual函数只会返回true或false,所以这里可以这样判断
          if (!deepEqual(value, value2)) {
            return false
          }
        } else if (value2 !== value) {
          return false
        }
      } else {
        return false
      }
    }
    // 上面所有的判断都不符合,就表示他们相同
    // 这里也是作为递归调用的一个出口
    return true
}
const a = {name: 'zs', age: 18, a: 1, b: null, c: false, d: [1, 2]}
const b = {name: 'zs', age: 18, a: 1, b: null, c: false, d: [1, 2]}

console.log(deepEqual(a, b))  // true

保守做法

为了避免背锅,工作中应该用lodash的isEqual方法判断对象是否相等

js
lodash.isEqual(obj1, obj2)