javascript - 通过 JavaScript 对象的共享来测试深度相等性

标签 javascript ecmascript-6

在 JavaScript 中测试两个对象的深度相等性这个主题上已经有很多笔墨。然而,似乎没有人关心区分以下两个对象:

var o1 = [{},{}];
var subitem = {};
var o2 = [subitem, subitem];
var o3 = [{}, {}];

大多数深度相等算法会说 o1o2o3 相等。我想要一个算法表明 o1o2 不相等,但 o1o3 相等。换句话说,我想要一个算法来告诉我指针 graphs 是否具有相同的结构。我关心这一点,因为如果我对第一个元素的修改反射(reflect)在 o2 中的第二个元素中,而不是在 o1 中。

这意味着循环结构的深度相等应该起作用:

var o1 = [];
o1.push(o1);
var o2 = [];
o2.push(o2);
// deepGraphEqual(o1, o2) == true
var o3 = [[]];
o3[0].push(o3);
// deepGraphEqual(o1, o3) == false

如果您要避免改变项目,您可能需要 ECMAScript6 映射,所以我会接受使用这些的解决方案。

最佳答案

没有 ES6 功能的以二次时间运行的版本:

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);
}

以线性时间运行的带有 ES6 Map 的版本:

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);
}

关于javascript - 通过 JavaScript 对象的共享来测试深度相等性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32793484/

相关文章:

javascript - 在 Jquery 中创建随机下落对象

javascript - 视差图像对我不起作用

javascript - 当鼠标按下时,如何根据鼠标悬停在哪个单元格上更改 html 表格单元格的颜色?

javascript - 如何在 Sequelize 查询中合并包含的模型属性

javascript - 使用 babel.js 无法在浏览器中导入/导出

node.js 扩展 foo 不是一个函数

javascript - 无法从导入的模块中找到函数

javascript - 正则表达式 - 匹配直到有相同数量的 2 个特定字符

Javascript:使用 try-catch 嵌套

javascript - 内存游戏 javascript 重置功能仅适用于最后两次点击