如何改进 Anders Kaseorg 的回答:
如果在非常大型数据结构上使用该算法,可能会出现堆栈溢出错误。例如,具有 5,000 个节点的完整图会发生这种情况。所以我写了一个非递归版本,它使用广度优先搜索而不是深度优先搜索,因为这似乎更容易实现(不使用递归时)。迭代版本适用于具有 5,000 个节点的完整图形(不过,在我的机器上需要 6 秒)。这里是:
function deepEqual(item1, item2){
var EQUAL_ATOM = 1, UNEQUAL = 2, OBJECT = 3;
function compareSimple(first, second){
var ty1 = typeof first, ty2 = typeof second;
if (ty1!==ty2) return UNEQUAL;
if (ty1!=='object'){
if (first===second) return EQUAL_ATOM;
if ((ty1==='number')&&isNaN(first)&&isNaN(second)) return EQUAL_ATOM;
return UNEQUAL;
}
if (first===null) return (second===null) ? EQUAL_ATOM : UNEQUAL;
if (second===null) return UNEQUAL;
if (Object.getPrototypeOf(first) !== Object.getPrototypeOf(second)) return UNEQUAL;
return OBJECT;
}
var c = compareSimple(item1, item2);
if (c !== OBJECT) { return (c===EQUAL_ATOM); }
var stack1 = [], stack2 = [], inverse1 = new Map(), inverse2 = new Map();
stack1.push(item1); stack2.push(item2);
inverse1.set(item1, 0); inverse2.set(item2, 0);
var currentIdx = 0;
var firstItem, secondItem, i, own, has1, has2, key, kid1, kid2, itemCount;
while (currentIdx < stack1.length){
firstItem = stack1[currentIdx]; secondItem = stack2[currentIdx];
own = {};
for (key in firstItem){
has1 = firstItem.hasOwnProperty(key);
has2 = secondItem.hasOwnProperty(key);
if (has1 !== has2) return false;
if (has1) { own[key] = null; }
}
for (key in secondItem){
if (!(key in own)){
has1 = firstItem.hasOwnProperty(key);
has2 = secondItem.hasOwnProperty(key);
if (has1 !== has2) return false;
if (has1) { own[key] = null; }
}
}
for (key in own){
kid1 = firstItem[key];
kid2 = secondItem[key];
c = compareSimple(kid1, kid2);
if (c === UNEQUAL) return false;
if (c === OBJECT){
has1 = inverse1.has(kid1);
has2 = inverse2.has(kid2);
if (has1 !== has2) return false;
if (has1){
if (inverse1.get(kid1) !== inverse2.get(kid2)) { return false; }
} else {
itemCount = stack1.length;
stack1.push(kid1); stack2.push(kid2);
inverse1.set(kid1, itemCount); inverse2.set(kid2, itemCount);
}
}
}
++currentIdx;
}
return true;
}
我在 jsperf.com 网站上添加了一些速度测试。有趣的是,根据数据结构,有时 Anders 的递归版本更快,有时我的迭代版本更快,平均而言,Anders 更受青睐。
这里是 jsperf 测试的链接:
nephews example
cycle free real world JSON from reddit example
uncles example
complete graph with 2K nodes
complete graph with 5K nodes
此外,内置对象不会以您可能想要的方式处理。许多或大多数内置对象“隐藏”它们的键。如果你做Object.keys(...),你只会得到一个空数组。
now = new Date();
keys = Object.keys(now); // result: []
因此,例如,任意 2 个 Dates 彼此是 deepGraphEqual,任意 2 个 RegExps 也是。这很可能不是你想要的。对于所有这些,我没有“包罗万象”,并且遍历所有现有的“内置”对象需要很长时间。但是对于Dates 和RegExps,here 是你可以放入更合理的东西,使用.toString() 来比较它们。