也许最简单的方法就是发布一个带有大量评论的函数来完成这项工作。递归部分位于传递给的函数的底部附近every:
// Helper to return a value's internal object [[Class]]
// That this returns [object Type] even for primitives
function getClass(obj) {
return Object.prototype.toString.call(obj);
}
/*
** @param a, b - values (Object, RegExp, Date, etc.)
** @returns {boolean} - true if a and b are the object or same primitive value or
** have the same properties with the same values
*/
function objectTester(a, b) {
// If a and b reference the same value, return true
if (a === b) return true;
// If a and b aren't the same type, return false
if (typeof a != typeof b) return false;
// Already know types are the same, so if type is number
// and both NaN, return true
if (typeof a == 'number' && isNaN(a) && isNaN(b)) return true;
// Get internal [[Class]]
var aClass = getClass(a);
var bClass = getClass(b)
// Return false if not same class
if (aClass != bClass) return false;
// If they're Boolean, String or Number objects, check values
if (aClass == '[object Boolean]' || aClass == '[object String]' || aClass == '[object Number]') {
return a.valueOf() == b.valueOf();
}
// If they're RegExps, Dates or Error objects, check stringified values
if (aClass == '[object RegExp]' || aClass == '[object Date]' || aClass == '[object Error]') {
return a.toString() == b.toString();
}
// Otherwise they're Objects, Functions or Arrays or some kind of host object
if (typeof a == 'object' || typeof a == 'function') {
// For functions, check stringigied values are the same
// Almost certainly false if a and b aren't trivial
// and are different functions
if (aClass == '[object Function]' && a.toString() != b.toString()) return false;
var aKeys = Object.keys(a);
var bKeys = Object.keys(b);
// If they don't have the same number of keys, return false
if (aKeys.length != bKeys.length) return false;
// Check they have the same keys
if (!aKeys.every(function(key){return b.hasOwnProperty(key)})) return false;
// Check key values - uses ES5 Object.keys
return aKeys.every(function(key){
return objectTester(a[key], b[key])
});
}
return false;
}
如果值/字符串不相同,则对 Date、RegExp、Error 等的测试可能应该返回 false,然后进行属性检查,但仅当您认为有人可能将属性附加到 Number 对象时才这样做(这是极其严重的)很少使用 Number 对象,更不用说向它们添加属性了,但我想这可能会发生)。
这里是:
/*
** @param a, b - values (Object, RegExp, Date, etc.)
** @returns {boolean} - true if a and b are the object or same primitive value or
** have the same properties with the same values
*/
function objectTester(a, b) {
// If a and b reference the same value, return true
if (a === b) return true;
// If a and b aren't the same type, return false
if (typeof a != typeof b) return false;
// Already know types are the same, so if type is number
// and both NaN, return true
if (typeof a == 'number' && isNaN(a) && isNaN(b)) return true;
// Get internal [[Class]]
var aClass = getClass(a);
var bClass = getClass(b)
// Return false if not same class
if (aClass != bClass) return false;
// If they're Boolean, String or Number objects, check values
if (aClass == '[object Boolean]' || aClass == '[object String]' || aClass == '[object Number]') {
if (a.valueOf() != b.valueOf()) return false;
}
// If they're RegExps, Dates or Error objects, check stringified values
if (aClass == '[object RegExp]' || aClass == '[object Date]' || aClass == '[object Error]') {
if (a.toString() != b.toString()) return false;
}
// For functions, check stringigied values are the same
// Almost impossible to be equal if a and b aren't trivial
// and are different functions
if (aClass == '[object Function]' && a.toString() != b.toString()) return false;
// For all objects, (including Objects, Functions, Arrays and host objects),
// check the properties
var aKeys = Object.keys(a);
var bKeys = Object.keys(b);
// If they don't have the same number of keys, return false
if (aKeys.length != bKeys.length) return false;
// Check they have the same keys
if (!aKeys.every(function(key){return b.hasOwnProperty(key)})) return false;
// Check key values - uses ES5 Object.keys
return aKeys.every(function(key){
return objectTester(a[key], b[key])
});
return false;
}