Unfortunately there is no perfect way, unless you use _proto_
recursively and access all non-enumerable properties, but this works in Firefox only.(不幸的是,没有完美的方法,除非您递归使用_proto_
并访问所有不可枚举的属性,但这仅在Firefox中有效。)
So the best I can do is to guess usage scenarios.(因此,我能做的最好是猜测使用情况。)
1) Fast and limited.(1)快速且有限。)
Works when you have simple JSON-style objects without methods and DOM nodes inside:(当您具有简单的JSON样式的对象,而内部没有方法和DOM节点时,则可以使用:)
JSON.stringify(obj1) === JSON.stringify(obj2)
The ORDER of the properties IS IMPORTANT, so this method will return false for following objects:(属性的ORDER重要,因此对于以下对象,此方法将返回false:)
x = {a: 1, b: 2};
y = {b: 2, a: 1};
2) Slow and more generic.(2)速度较慢,通用性更高。)
Compares objects without digging into prototypes, then compares properties' projections recursively, and also compares constructors.(在不深入研究原型的情况下比较对象,然后递归比较属性的投影,还比较构造函数。)
This is almost correct algorithm:(这几乎是正确的算法:)
function deepCompare () {
var i, l, leftChain, rightChain;
function compare2Objects (x, y) {
var p;
// remember that NaN === NaN returns false
// and isNaN(undefined) returns true
if (isNaN(x) && isNaN(y) && typeof x === 'number' && typeof y === 'number') {
return true;
}
// Compare primitives and functions.
// Check if both arguments link to the same object.
// Especially useful on the step where we compare prototypes
if (x === y) {
return true;
}
// Works in case when functions are created in constructor.
// Comparing dates is a common scenario. Another built-ins?
// We can even handle functions passed across iframes
if ((typeof x === 'function' && typeof y === 'function') ||
(x instanceof Date && y instanceof Date) ||
(x instanceof RegExp && y instanceof RegExp) ||
(x instanceof String && y instanceof String) ||
(x instanceof Number && y instanceof Number)) {
return x.toString() === y.toString();
}
// At last checking prototypes as good as we can
if (!(x instanceof Object && y instanceof Object)) {
return false;
}
if (x.isPrototypeOf(y) || y.isPrototypeOf(x)) {
return false;
}
if (x.constructor !== y.constructor) {
return false;
}
if (x.prototype !== y.prototype) {
return false;
}
// Check for infinitive linking loops
if (leftChain.indexOf(x) > -1 || rightChain.indexOf(y) > -1) {
return false;
}
// Quick checking of one object being a subset of another.
// todo: cache the structure of arguments[0] for performance
for (p in y) {
if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
return false;
}
else if (typeof y[p] !== typeof x[p]) {
return false;
}
}
for (p in x) {
if (y.hasOwnProperty(p) !== x.hasOwnProperty(p)) {
return false;
}
else if (typeof y[p] !== typeof x[p]) {
return false;
}
switch (typeof (x[p])) {
case 'object':
case 'function':
leftChain.push(x);
rightChain.push(y);
if (!compare2Objects (x[p], y[p])) {
return false;
}
leftChain.pop();
rightChain.pop();
break;
default:
if (x[p] !== y[p]) {
return false;
}
break;
}
}
return true;
}
if (arguments.length < 1) {
return true; //Die silently? Don't know how to handle such case, please help...
// throw "Need two or more arguments to compare";
}
for (i = 1, l = arguments.length; i < l; i++) {
leftChain = []; //Todo: this can be cached
rightChain = [];
if (!compare2Objects(arguments[0], arguments[i])) {
return false;
}
}
return true;
}
Known issues (well, they have very low priority, probably you'll never notice them):(已知问题(嗯,它们的优先级很低,可能您永远不会注意到它们):)
objects with different prototype structure but same projection(具有不同原型结构但投影相同的对象)
functions may have identical text but refer to different closures(函数可能具有相同的文本,但是引用了不同的闭包)
Tests: passes tests are from How to determine equality for two JavaScript objects?(测试:通过测试来自于如何确定两个JavaScript对象的相等性?) .(。) 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…