Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【Q598】如何实现一个深比较的函数 deepEqual #614

Open
shfshanyue opened this issue Jun 13, 2021 · 3 comments
Open

【Q598】如何实现一个深比较的函数 deepEqual #614

shfshanyue opened this issue Jun 13, 2021 · 3 comments

Comments

@shfshanyue
Copy link
Owner

No description provided.

@haotie1990
Copy link

function isEqual(x, y) {
  if (x === y) {
    return true;
  } else if ((typeof x === 'object' && x !== null) && (typeof y === 'object' && y !== null)) {
    const keysX = Object.keys(x);
    const keysY = Object.keys(y);
    if (keysX.length !== keysY.length) {
      return false;
    }
    for (const key of keysX) {
      if(!isEqual(x[key], y[key])) {
        return false;
      }
    }
    return true;
  } else {
    return false;
  }
}

@shfshanyue
Copy link
Owner Author

TODO

@justorez
Copy link

const typeOf = (val) => Object.prototype.toString.call(val).slice(8, -1)
const isFunction = (val) => typeOf(val) === 'Function'

function eq(a, b, aStack, bStack) {
    // === 结果为 true 的区别出 +0 和 -0
    if (a === b) return a !== 0 || 1 / a === 1 / b

    // typeof null 的结果为 object,这里做判断,是为了让有 null 的情况尽早退出函数
    if (a == null || b == null) return false

    // 判断 NaN
    if (a !== a) return b !== b

    // 判断参数 a 类型,如果是基本类型,在这里可以直接返回 false
    const type = typeof a
    if (type !== 'function' && type !== 'object' && typeof b != 'object') {
        return false
    }

    // 更复杂的对象使用 deepEq 函数进行深度比较
    return deepEq(a, b, aStack, bStack)
}

function deepEq(a, b, aStack, bStack) {
    // a 和 b 的内部属性 [[class]] 相同时 返回 true
    const className = typeOf(a)
    if (className !== typeOf(b)) return false

    switch (className) {
        case 'RegExp':
        case 'String':
            return '' + a === '' + b
        case 'Number':
            if (+a !== +a) return +b !== +b
            return +a === 0 ? 1 / +a === 1 / +b : +a === +b
        case 'Date':
        case 'Boolean':
            return +a === +b
    }

    const areArrays = className === 'Array'
    // 不是数组
    if (!areArrays) {
        // 过滤掉两个函数的情况
        if (typeof a != 'object' || typeof b != 'object') return false

        const aCtor = a.constructor,
            bCtor = b.constructor
        // aCtor 和 bCtor 必须都存在并且都不是 Object 构造函数的情况下,
        // aCtor 不等于 bCtor, 那这两个对象就真的不相等啦
        if (
            aCtor !== bCtor &&
            !(
                isFunction(aCtor) &&
                aCtor instanceof aCtor &&
                isFunction(bCtor) &&
                bCtor instanceof bCtor
            ) &&
            'constructor' in a &&
            'constructor' in b
        ) {
            return false
        }
    }

    aStack = aStack || []
    bStack = bStack || []
    let length = aStack.length

    // 检查是否有循环引用的部分
    while (length--) {
        if (aStack[length] === a) {
            return bStack[length] === b
        }
    }

    aStack.push(a)
    bStack.push(b)

    // 数组判断
    if (areArrays) {
        length = a.length
        if (length !== b.length) return false

        while (length--) {
            if (!eq(a[length], b[length], aStack, bStack)) return false
        }
    }
    // 对象判断
    else {
        let keys = Object.keys(a),
            key = -1,
            length = keys.length

        if (Object.keys(b).length !== length) return false
        while (length--) {
            key = keys[length]
            if (!(b.hasOwnProperty(key) && eq(a[key], b[key], aStack, bStack)))
                return false
        }
    }

    aStack.pop()
    bStack.pop()
    return true
}

代码来源:JavaScript专题之如何判断两个对象相等

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants