I am implementing a function that compares two JavaScript objects for "deep" equality. The skeleton of this function, right now, looks like this:
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);
}
The question is what to put where it says // ??? cyclic reference detected
. Ideally, I would like to be able to say that these objects are deep-equal:
var a = {foo:1, bar:2, baz:null},
b = {foo:1, bar:2, baz:null};
a.baz = a;
b.baz = b;
and these objects are not deep-equal:
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;
Notes:
assert
throws an exception if its argument is false.have_all_the_same_properties(x, y)
throws an exception if thegetOwnPropertyNames
lists ofx
andy
are not identical.is_scalar(x)
is effectively the same astypeof x !== 'object'
.- I used a for-of loop in the code above for brevity's sake, but ES6 features are not available in the interpreter this will actually run on.