问题描述:  

  在JavaScript中,数值的比较是比较简单的,使用相等(==)和全等(===)符号基本上可以解决大多数非对象的比较;但是相等(==)和全等(===)符号在对象 object 的比较上,就不能满足所有的要求了,如下面的代码:

 1 let obj_a = {
 2 name: "jack",
 3     old: 12
 4 }
 5 
 6 let obj_b = {
 7     name: "lucy",
 8     old: 13
 9 }
10 
11 let obj_c = {
12     name: "lucy",
13     old: 13
14 }
15 
16 let obj_d = obj_b
17 
18 console.log(obj_a === obj_b) // false
19 console.log(obj_b === obj_c) // false
20 console.log(obj_b === obj_d) // true

  上面代码中 obj_b 和 obj_c 是不等的,但是和 obj_d 是相等的,这是因为全等符号 === 在比较对象的时候,比较的是对象的地址,换句话来说:全等符号判断的是两个对象是否是一个对象,而不能判断两个对象是否数值相等,事实上,在大多数情况下,使用全等符号去判断两个对象返回的均是 false

解决方法:

  那如果需要判断两个对象在字面意义上是否相等,该才去什么样的操作?答案是遍历两个对象,然后在一一比较 key-value 对;如果对象发生了嵌套, 那么使用递归即可; 为了方便使用,可以将比较的方法抽象成为下面的函数:

const isObjectValueEqual = (a, b) => {
    // Object.getOwnPropertyNames()方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组
    // 换句话来说 Object.getOwnPropertyNames()方法返回的是对象所有 key 组成的数组 list
    let aProps = Object.getOwnPropertyNames(a)
    let bProps = Object.getOwnPropertyNames(b)
    if (aProps.length != bProps.length) {
        return false
    }

    for (let i = 0; i < aProps.length; i++) {
        let propName = aProps[i]
        if (typeof a[propName] === 'object') {
            let judge = isObjectValueEqual(a[propName], b[propName])
            if (!judge) {
                return false
            }
        } else if (a[propName] !== b[propName]) {
            return false
        }
    }
    return true
}

 

结论:

  1)===主要用于判断对象是否是同一个对象,而不能用来判断两个存储地址不一致的对象在属性上是否完全相等

  2)判断存储地址不一致的对象在属性上是否完全相等可以使用如上函数

  3)普通变量可以使用 set 集合的方法方便地去重,但是对象变量是不能的(这点可以自己验证)