_.isEqual: Move the internal eq method into the main closure. Remove strict type checking.

This commit is contained in:
Kit Goncharov
2011-07-12 20:22:05 -06:00
parent e21b346cbf
commit 9d0b43221a

View File

@@ -593,64 +593,63 @@
return obj; return obj;
}; };
// Perform a deep comparison to check if two objects are equal. // Internal recursive comparison function.
_.isEqual = (function() { function eq(a, b, stack) {
function eq(a, b, stack) { // Identical objects are equal.
// Identical objects are equal. if (a === b) return true;
if (a === b) return true; // A strict comparison is necessary because `null == undefined`.
// A strict comparison is necessary because `null == undefined`. if (a == null) return a === b;
if (a == null) return a === b; // Compare object types.
// Compare object types. var typeA = typeof a;
var typeA = typeof a; if (typeA != typeof b) return false;
if (typeA != typeof b) return false; // The type comparison above prevents unwanted type coercion.
// Compare functions by reference. if (a == b) return true;
if (_.isFunction(a)) return _.isFunction(b) && a == b; // Ensure that both values are truthy or falsy.
// Compare strings, numbers, dates, and booleans by value. if ((!a && b) || (a && !b)) return false;
if (_.isString(a)) return _.isString(b) && String(a) == String(b); // `NaN` values are toxic.
if (_.isNumber(a)) return _.isNumber(b) && +a == +b; if (_.isNaN(a) || _.isNaN(b)) return false;
if (_.isDate(a)) return _.isDate(b) && a.getTime() == b.getTime(); if (_.isDate(a)) return _.isDate(b) && a.getTime() == b.getTime();
if (_.isBoolean(a)) return _.isBoolean(b) && +a == +b; // Compare RegExps by their source patterns and flags.
// Compare RegExps by their source patterns and flags. if (_.isRegExp(a)) return _.isRegExp(b) && a.source == b.source &&
if (_.isRegExp(a)) return _.isRegExp(b) && a.source == b.source && a.global == b.global &&
a.global == b.global && a.multiline == b.multiline &&
a.multiline == b.multiline && a.ignoreCase == b.ignoreCase;
a.ignoreCase == b.ignoreCase; // Recursively compare objects and arrays.
// Recursively compare objects and arrays. if (typeA != 'object') return false;
if (typeA != 'object') return false; // Unwrap any wrapped objects.
// Unwrap any wrapped objects. if (a._chain) a = a._wrapped;
if (a._chain) a = a._wrapped; if (b._chain) b = b._wrapped;
if (b._chain) b = b._wrapped; // Invoke a custom `isEqual` method if one is provided.
// Invoke a custom `isEqual` method if one is provided. if (a.isEqual) return a.isEqual(b);
if (a.isEqual) return a.isEqual(b); if (b.isEqual) return b.isEqual(a);
if (b.isEqual) return b.isEqual(a); // Compare array lengths to determine if a deep comparison is necessary.
// Compare array lengths to determine if a deep comparison is necessary. if (a.length && (a.length !== b.length)) return false;
if (a.length && (a.length !== b.length)) return false; // Assume equality for cyclic structures.
// Assume equality for cyclic structures. var length = stack.length;
var length = stack.length; while (length--) {
while (length--) { if (stack[length] == a) return true;
if (stack[length] == a) return true;
}
// Add the object to the stack of traversed objects.
stack.push(a);
var result = true;
// Deep comparse the contents.
var aKeys = _.keys(a), bKeys = _.keys(b);
// Ensure that both objects contain the same number of properties.
if (result = aKeys.length == bKeys.length) {
// Recursively compare properties.
for (var key in a) {
if (!(result = key in b && eq(a[key], b[key], stack))) break;
}
}
// Remove the object from the stack of traversed objects.
stack.pop();
return result;
} }
// Expose the recursive `isEqual` method. // Add the object to the stack of traversed objects.
return function(a, b) { stack.push(a);
return eq(a, b, []); var result = true;
}; // Deep comparse the contents.
})(); var aKeys = _.keys(a), bKeys = _.keys(b);
// Ensure that both objects contain the same number of properties.
if (result = aKeys.length == bKeys.length) {
// Recursively compare properties.
for (var key in a) {
if (!(result = key in b && eq(a[key], b[key], stack))) break;
}
}
// Remove the object from the stack of traversed objects.
stack.pop();
return result;
}
// Perform a deep comparison to check if two objects are equal.
_.isEqual = function(a, b) {
return eq(a, b, []);
};
// Is a given array or object empty? // Is a given array or object empty?
_.isEmpty = function(obj) { _.isEmpty = function(obj) {