手写深度比较:isEqual

1,629 阅读2分钟
  • 思想跟深拷贝类似。
  • 这里不考虑 function,比较 function 没意义。
  1. 首先判断是不是引用类型,这里定义一个 isObject 方法:
function isObject(obj) {
    return (typeof obj === 'object' && null !== obj);
}
  1. 定义好 isObject 之后在 isEqual 里头首先要使用它来判断是不是引用类型,如果不是引用类型,可以判断其一或其二为值类型,我们直接三等比较即可。
    // 1.判断是不是引用类型,某一者不是引用类型直接比较
    if(!isObject(obj1) || !isObject(obj2)) {
        return obj1 === obj2;
    }
  1. 如果确定是引用类型了,那么还需要考虑另外一种情况就是传递进来的 obj2 和 obj1 有可能是某一者浅拷贝出来的,或者有可能它们根本就是同一个。比如:

isEqual(obj1, obj1);

或者

const obj3 = obj1; isEqual(obj1, obj3);

这时候我们直接返回 true。

    // 2.比较是否为同一个内存地址
    if (obj1 === obj2) return true;
  1. 比较 key 的数量是否一致,如果不一致直接不用继续判断 value 了,直接返回 false
// 3.比较 key 的数量
    const obj1KeysLength = Object.keys(obj1).length;
    const obj2KeysLength = Object.keys(obj2).length;
    if(obj1KeysLength !== obj2KeysLength) return false;
  1. key 的数量确定了,到这里就可以直接比较 value 了,因为对象可能含有对象,我们使用递归即可层层遍历里面,只要有一个值不一样就返回 false。
// 4.比较 value 的值
    for (let key in obj1) {
        const result = isEqual(obj1[key], obj2[key]);
        if(!result) return false;
    }
    return true;

将上面 5 大步骤整合到一个方法:isEqual

function isEqual(obj1, obj2) {
    // 1.判断是不是引用类型,不是引用
    if (!isObject(obj1) || !isObject(obj2)) {
        return obj1 === obj2;
    }
    // 2.比较是否为同一个内存地址
    if (obj1 === obj2) return true;
    // 3.比较 key 的数量
    const obj1KeysLength = Object.keys(obj1).length;
    const obj2KeysLength = Object.keys(obj2).length;
    if (obj1KeysLength !== obj2KeysLength) return false;
    // 4.比较 value 的值
    for (let key in obj1) {
        const result = isEqual(obj1[key], obj2[key]);
        if(!result) return false;
    }
    return true;
}

测试是否可行,可自行修改测试数据进行测试:

const obj1 = {
    a: 100,
    b: {
        x: 200,
        y: 300
    },
    c: 400
}

const obj2 = {
    a: 100,
    b: {
        x: 200,
        y: 300
    },
    c: 400
}

console.log(obj1 === obj1);        // true
console.log(obj1 === obj2);        // false
console.log(isEqual(obj1, obj1));  // true
console.log(isEqual(obj1, obj2));  // true

下面是完整的代码,方便COPY:

function isObject(obj) {
    return (typeof obj === 'object' && null !== obj);
}

function isEqual(obj1, obj2) {
    // 1.判断是不是引用类型,不是引用
    if (!isObject(obj1) || !isObject(obj2)) {
        return obj1 === obj2;
    }
    // 2.比较是否为同一个内存地址
    if (obj1 === obj2) return true;
    // 3.比较 key 的数量
    const obj1KeysLength = Object.keys(obj1).length;
    const obj2KeysLength = Object.keys(obj2).length;
    if (obj1KeysLength !== obj2KeysLength) return false;
    // 4.比较 value 的值
    for (let key in obj1) {
        const result = isEqual(obj1[key], obj2[key]);
        if(!result) return false;
    }
    return true;
}

const obj1 = {
    a: 100,
    b: {
        x: 200,
        y: 300
    },
    c: 400
}

const obj2 = {
    a: 100,
    b: {
        x: 200,
        y: 300
    },
    c: 400
}

console.log(obj1 === obj1);
console.log(obj1 === obj2);
console.log(isEqual(obj1, obj1));
console.log(isEqual(obj1, obj2));