mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-01 15:57:48 +00:00
Add support for comparing string, number, and boolean object wrappers. Ignore inherited properties when deep comparing objects. Use a more efficient while loop for comparing arrays and array-like objects.
This commit is contained in:
@@ -603,23 +603,29 @@
|
||||
// Compare object types.
|
||||
var typeA = typeof a;
|
||||
if (typeA != typeof b) return false;
|
||||
// The type comparison above prevents unwanted type coercion.
|
||||
if (a == b) return true;
|
||||
// Optimization; ensure that both values are truthy or falsy.
|
||||
if (!a != !b) return false;
|
||||
// `NaN` values are equal.
|
||||
if (_.isNaN(a)) return _.isNaN(b);
|
||||
// Compare string objects by value.
|
||||
var isStringA = _.isString(a), isStringB = _.isString(b);
|
||||
if (isStringA || isStringB) return isStringA && isStringB && String(a) == String(b);
|
||||
// Compare number objects by value. `NaN` values are equal.
|
||||
var isNumberA = toString.call(a) == '[object Number]', isNumberB = toString.call(b) == '[object Number]';
|
||||
if (isNumberA || isNumberB) return isNumberA && isNumberB && (_.isNaN(a) ? _.isNaN(b) : +a == +b);
|
||||
// Compare boolean objects by value. The value of `true` is 1; the value of `false` is 0.
|
||||
var isBooleanA = toString.call(a) == '[object Boolean]', isBooleanB = toString.call(b) == '[object Boolean]';
|
||||
if (isBooleanA || isBooleanB) return isBooleanA && isBooleanB && +a == +b;
|
||||
// Compare dates by their millisecond values.
|
||||
var isDateA = _.isDate(a), isDateB = _.isDate(b);
|
||||
if (isDateA || isDateB) return isDateA && isDateB && a.getTime() == b.getTime();
|
||||
// Compare RegExps by their source patterns and flags.
|
||||
var isRegExpA = _.isRegExp(a), isRegExpB = _.isRegExp(b);
|
||||
if (isRegExpA || isRegExpB)
|
||||
return isRegExpA && isRegExpB &&
|
||||
a.source == b.source &&
|
||||
a.global == b.global &&
|
||||
a.multiline == b.multiline &&
|
||||
a.ignoreCase == b.ignoreCase;
|
||||
// Ensure commutative equality for RegExps.
|
||||
return isRegExpA && isRegExpB &&
|
||||
a.source == b.source &&
|
||||
a.global == b.global &&
|
||||
a.multiline == b.multiline &&
|
||||
a.ignoreCase == b.ignoreCase;
|
||||
// Ensure that both values are objects.
|
||||
if (typeA != 'object') return false;
|
||||
// Unwrap any wrapped objects.
|
||||
@@ -627,30 +633,47 @@
|
||||
if (b._chain) b = b._wrapped;
|
||||
// Invoke a custom `isEqual` method if one is provided.
|
||||
if (typeof a.isEqual == 'function') return a.isEqual(b);
|
||||
if (typeof b.isEqual == 'function') return b.isEqual(a);
|
||||
// Compare array lengths to determine if a deep comparison is necessary.
|
||||
if ('length' in a && (a.length !== b.length)) return false;
|
||||
// Assume equality for cyclic structures.
|
||||
// If only `b` provides an `isEqual` method, `a` and `b` are not equal.
|
||||
if (typeof b.isEqual == 'function') return false;
|
||||
// Assume equality for cyclic structures. The algorithm for detecting cyclic structures is
|
||||
// adapted from ES 5.1 section 15.12.3, abstract operation `JO`.
|
||||
var length = stack.length;
|
||||
while (length--) {
|
||||
// Linear search. Performance is inversely proportional to the number of unique nested
|
||||
// structures.
|
||||
if (stack[length] == a) return true;
|
||||
}
|
||||
// Add the first object to the stack of traversed objects.
|
||||
stack.push(a);
|
||||
// Deep compare the two objects.
|
||||
var size = 0, sizeRight = 0, result = true, key;
|
||||
for (key in a) {
|
||||
// Count the expected number of properties.
|
||||
size++;
|
||||
// Deep compare each member.
|
||||
if (!(result = key in b && eq(a[key], b[key], stack))) break;
|
||||
}
|
||||
// Ensure that both objects contain the same number of properties.
|
||||
if (result) {
|
||||
for (key in b) {
|
||||
if (++sizeRight > size) break;
|
||||
var size = 0, result = true;
|
||||
if (a.length === +a.length || b.length === +b.length) {
|
||||
// Compare object lengths to determine if a deep comparison is necessary.
|
||||
size = a.length;
|
||||
result = size == b.length;
|
||||
if (result) {
|
||||
// Deep compare array-like object contents, ignoring non-numeric properties.
|
||||
while (size--) {
|
||||
// Ensure commutative equality for sparse arrays.
|
||||
if (!(result = size in a == size in b && eq(a[size], b[size], stack))) break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Deep compare objects.
|
||||
for (var key in a) {
|
||||
if (hasOwnProperty.call(a, key)) {
|
||||
// Count the expected number of properties.
|
||||
size++;
|
||||
// Deep compare each member.
|
||||
if (!(result = hasOwnProperty.call(b, key) && eq(a[key], b[key], stack))) break;
|
||||
}
|
||||
}
|
||||
// Ensure that both objects contain the same number of properties.
|
||||
if (result) {
|
||||
for (key in b) {
|
||||
if (hasOwnProperty.call(b, key) && !size--) break;
|
||||
}
|
||||
result = !size;
|
||||
}
|
||||
result = size == sizeRight;
|
||||
}
|
||||
// Remove the first object from the stack of traversed objects.
|
||||
stack.pop();
|
||||
|
||||
Reference in New Issue
Block a user