深度比较isEqual

434 阅读1分钟

需求

实现输入任意两个类型的数据a,b,isEqual都能准确地判断是否相等(不比较函数)

注解:不比较函数;考虑symbol键;相同value的不同类型入参会被错误判断成相等。

分析

  1. 比较所有键值对,不是引用类型直接返回比较结果,return ====;
  2. 地址相等的对象直接返回true;
  3. 两个都是对象||数组:比较key个数,以obj1为基准,依次比较;

代码

// 判断是否为引用类型
function isObject(obj) {
    return typeof obj === 'object' && obj !== null;
}

// 相同value的不同类型入参会被错误判断成相等
/*
const a = [1, 2, 3]
const b = {0: 1, 1: 2, 2:3}
isEqual(a, b) // 理应是false,但会得到true
*/
function isSameType(obj1, obj2) {
    return Object.prototype.toString.call(obj1) === Object.prototype.toString.call(obj2)
}

// 全相等(深度)
function isEqual(obj1, obj2) {
    if (!isObject(obj1) || !isObject(obj2)) {
        // 不是引用类型直接返回结果
        return obj1 === obj2
    }
    // 判断是否同一个地址
    if (obj1 === obj2) {
        return true
    }
    
    if (!isSameType(obj1, obj2)) { 
        return false
    }

    // 都是对象或数组,且不相等
    // 先取出obj1和obj2的 keys,包括symbol的key,比较个数
    const obj1Keys = [...Object.keys(obj1), ...Object.getOwnPropertySymbols(obj1)];
    const obj2Keys = [...Object.keys(obj2), ...Object.getOwnPropertySymbols(obj2)];
    if (obj1Keys.length !== obj2Keys.length) {
        return false;
    }
    // 以obj1为基准,和obj2一次递归比较
    for (let key in obj1) {
        if (obj1[key] !== obj2[key]) {
            return false;
        }
        // 比较当前key的val —— 递归
        const res = isEqual(obj1[key], obj2[key])
        if (!res) {
            return false
        }
    }
    // 全相等
    return true;
}