Test deep equality *with sharing* of JavaScript objects

前端 未结 2 1103
余生分开走
余生分开走 2021-01-13 07:22

Much ink has been spilled on the subject of testing two objects for deep equality in JavaScript. None, however, seem to care about distinguishing the following two objects:<

2条回答
  •  渐次进展
    2021-01-13 08:08

    Version with no ES6 features that runs in quadratic time:

    function deepGraphEqual(a, b) {
        var left = [], right = [], has = Object.prototype.hasOwnProperty;
        function visit(a, b) {
            var i, k;
            if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null)
                return a === b;
            if (Object.getPrototypeOf(a) !== Object.getPrototypeOf(b))
                return false;
            for (i = 0; i < left.length; i++) {
                if (a === left[i])
                    return b === right[i];
                if (b === right[i])
                    return a === left[i];
            }
            for (k in a)
                if (has.call(a, k) && !has.call(b, k))
                    return false;
            for (k in b)
                if (has.call(b, k) && !has.call(a, k))
                    return false;
            left.push(a);
            right.push(b);
            for (k in a)
                if (has.call(a, k) && !visit(a[k], b[k]))
                    return false;
            return true;
        }
        return visit(a, b);
    }
    

    Version with ES6 Map that runs in linear time:

    function deepGraphEqual(a, b) {
        let left = new Map(), right = new Map(), has = Object.prototype.hasOwnProperty;
        function visit(a, b) {
            if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null)
                return a === b;
            if (Object.getPrototypeOf(a) !== Object.getPrototypeOf(b))
                return false;
            if (left.has(a))
                return left.get(a) === b
            if (right.has(b))
                return right.get(b) === a
            for (let k in a)
                if (has.call(a, k) && !has.call(b, k))
                    return false;
            for (let k in b)
                if (has.call(b, k) && !has.call(a, k))
                    return false;
            left.set(a, b);
            right.set(b, a);
            for (let k in a)
                if (has.call(a, k) && !visit(a[k], b[k]))
                    return false;
            return true;
        }
        return visit(a, b);
    }
    

提交回复
热议问题