javascript - 检测对象A中的循环引用是否与对象B中的循环引用在结构上相同

标签 javascript object cyclic-reference

我正在实现一个函数来比较两个 JavaScript 对象的“深度”相等性。这个函数的框架现在看起来像这样:

function check_equal(actual, expected) {
    var stack = [];
    function check_equal_r(act, exp) {
        if (is_scalar(act) || is_scalar(exp)) {
            assert(act === exp);

        } else if (stack.indexOf(act) == -1) {
            assert(have_all_the_same_properties(act, exp));
            stack.push(act);
            for (var k of Object.getOwnPropertyNames(exp)) {
                check_equal_r(act[k], exp[k]);
            }
            stack.pop(act);

        } else {
            // ??? cyclic reference detected
        }
    }
    check_equal_r(act, exp);
}

问题是在它说的地方放什么 //???检测到循环引用。理想情况下,我希望能够说这些对象是深度相等的:

var a = {foo:1, bar:2, baz:null},
    b = {foo:1, bar:2, baz:null};
a.baz = a;
b.baz = b;

并且这些对象深度相等:

var a = { car: 1, cdr: { car: 2, cdr: null } };
var b = { car: 1, cdr: { car: 2, cdr: null } };
a.cdr.cdr = a;
b.cdr.cdr = b.cdr;

注意事项:

  • assert 如果其参数为假则抛出异常。
  • have_all_the_same_properties(x, y) 如果 xygetOwnPropertyNames 列表不是,则抛出异常相同。
  • is_scalar(x) 有效地typeof x !== 'object' 相同。
  • 为了简洁起见,我在上面的代码中使用了 for-of 循​​环,但是 ES6 特性在实际运行的解释器中不可用。

最佳答案

这是一个非常简单的算法扩展,用于检查循环引用。它将对应于每个 act 对象的 exp 保存在一个单独的堆栈中,这样它将与在其中引用的任何 act 具有相同的索引本身。

function is_scalar(v) {
    return typeof v !== 'object';
}

function have_all_the_same_properties(x, y) {
    var xprops = Object.getOwnPropertyNames(x),
        yprops = Object.getOwnPropertyNames(y);
    if (xprops.length === yprops.length) {
        return xprops.every(function (prop) {
            return yprops.indexOf(prop) !== -1;
        });
    }
    return false;
}

function check_equal(actual, expected) {
    var stack = [];
    var expected_stack = [];
    function check_equal_r(act, exp) {
        if (is_scalar(act) || is_scalar(exp)) {
            return act === exp;
        } else {
            var i = stack.indexOf(act);
            if (i == -1) {
                if (have_all_the_same_properties(act, exp)) {
                    stack.push(act);
                    expected_stack.push(exp);
                    var res = Object.getOwnPropertyNames(exp).every(function (k) {
                        return check_equal_r(act[k], exp[k]);
                    });
                    expected_stack.pop();
                    stack.pop();
                    return res;
                } else {
                    return false;
                }
            } else {
                return expected_stack[i] === exp;
            }
        }
    }
    return check_equal_r(actual, expected);
}

var a = {foo:1, bar:2, baz:null},
    b = {foo:1, bar:2, baz:null};
a.baz = a;
b.baz = b;

console.log(check_equal(a, b));

var c = { car: 1, cdr: { car: 2, cdr: null } };
var d = { car: 1, cdr: { car: 2, cdr: null } };
c.cdr.cdr = c;
d.cdr.cdr = d.cdr;

console.log(check_equal(c, d));

关于javascript - 检测对象A中的循环引用是否与对象B中的循环引用在结构上相同,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32189551/

相关文章:

使用 from package import module 语法时 Python 循环导入失败

perl - 防止 Perl 中的循环引用内存泄漏

javascript - 如何使用fengyuanchen/cropper裁剪图像并将图像裁剪的路径保存在数据库中?

javascript - 获取表格中的特定列

javascript - 获取对象所有Lodash路径的数组

sql-server - 如何删除基于 sys.objects 的表?

javascript - Microsoft JScript 运行时错误 : 'WScript' is undefined

javascript - Javascript中的一组数字对

iphone - 如何调用applicationDidEnterBackground中的函数?

javascript - 在代码中找到一个圆形对象