mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-09 18:37:50 +00:00
Cleanup _.isEqual and make _.where of an empty array match all arrays similar to empty objects matching all objects.
This commit is contained in:
178
lodash.js
178
lodash.js
@@ -1926,38 +1926,18 @@
|
|||||||
if (valClass != othClass) {
|
if (valClass != othClass) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
switch (valClass) {
|
|
||||||
case boolClass:
|
|
||||||
case dateClass:
|
|
||||||
// coerce dates and booleans to numbers, dates to milliseconds and booleans
|
|
||||||
// to `1` or `0` treating invalid dates coerced to `NaN` as not equal
|
|
||||||
return +value == +other;
|
|
||||||
|
|
||||||
case numberClass:
|
|
||||||
// treat `NaN` vs. `NaN` as equal
|
|
||||||
return (value != +value)
|
|
||||||
? other != +other
|
|
||||||
// but treat `-0` vs. `+0` as not equal
|
|
||||||
: (value == 0 ? (1 / value == 1 / other) : value == +other);
|
|
||||||
|
|
||||||
case regexpClass:
|
|
||||||
case stringClass:
|
|
||||||
// coerce regexes to strings (http://es5.github.io/#x15.10.6.4) and
|
|
||||||
// treat strings primitives and string objects as equal
|
|
||||||
return value == String(other);
|
|
||||||
}
|
|
||||||
var isArr = arrayLikeClasses[valClass],
|
var isArr = arrayLikeClasses[valClass],
|
||||||
isErr = valClass == errorClass;
|
isErr = valClass == errorClass;
|
||||||
|
|
||||||
if (!support.argsClass) {
|
if (isArr) {
|
||||||
valIsArg = isArguments(value);
|
var valLength = value.length,
|
||||||
othIsArg = isArguments(other);
|
othLength = other.length;
|
||||||
}
|
|
||||||
if (!isArr) {
|
if (valLength != othLength && !(isWhere && othLength > valLength)) {
|
||||||
// exit for things like functions and DOM nodes
|
|
||||||
if (!(isErr || valClass == objectClass) || (!support.nodeClass && (isNode(value) || isNode(other)))) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if (isErr || (valClass == objectClass && (support.nodeClass || !(isNode(value) || isNode(other))))) {
|
||||||
// unwrap any `lodash` wrapped values
|
// unwrap any `lodash` wrapped values
|
||||||
var valWrapped = hasOwnProperty.call(value, '__wrapped__'),
|
var valWrapped = hasOwnProperty.call(value, '__wrapped__'),
|
||||||
othWrapped = hasOwnProperty.call(other, '__wrapped__');
|
othWrapped = hasOwnProperty.call(other, '__wrapped__');
|
||||||
@@ -1965,6 +1945,10 @@
|
|||||||
if (valWrapped || othWrapped) {
|
if (valWrapped || othWrapped) {
|
||||||
return baseIsEqual(valWrapped ? value.__wrapped__ : value, othWrapped ? other.__wrapped__ : other, customizer, isWhere, stackA, stackB);
|
return baseIsEqual(valWrapped ? value.__wrapped__ : value, othWrapped ? other.__wrapped__ : other, customizer, isWhere, stackA, stackB);
|
||||||
}
|
}
|
||||||
|
if (!support.argsClass) {
|
||||||
|
valIsArg = isArguments(value);
|
||||||
|
othIsArg = isArguments(other);
|
||||||
|
}
|
||||||
var hasValCtor = !valIsArg && hasOwnProperty.call(value, 'constructor'),
|
var hasValCtor = !valIsArg && hasOwnProperty.call(value, 'constructor'),
|
||||||
hasOthCtor = !othIsArg && hasOwnProperty.call(other, 'constructor');
|
hasOthCtor = !othIsArg && hasOwnProperty.call(other, 'constructor');
|
||||||
|
|
||||||
@@ -1988,57 +1972,6 @@
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// assume cyclic structures are equal
|
|
||||||
// the algorithm for detecting cyclic structures is adapted from ES 5.1
|
|
||||||
// section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3)
|
|
||||||
stackA || (stackA = []);
|
|
||||||
stackB || (stackB = []);
|
|
||||||
|
|
||||||
var length = stackA.length;
|
|
||||||
while (length--) {
|
|
||||||
if (stackA[length] == value) {
|
|
||||||
return stackB[length] == other;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var index = -1;
|
|
||||||
|
|
||||||
// add `value` and `other` to the stack of traversed objects
|
|
||||||
stackA.push(value);
|
|
||||||
stackB.push(other);
|
|
||||||
|
|
||||||
// recursively compare objects and arrays (susceptible to call stack limits)
|
|
||||||
if (isArr) {
|
|
||||||
var othLength = other.length;
|
|
||||||
length = value.length;
|
|
||||||
result = length == othLength;
|
|
||||||
|
|
||||||
if (result || (isWhere && othLength > length)) {
|
|
||||||
// deep compare the contents, ignoring non-numeric properties
|
|
||||||
while (++index < length) {
|
|
||||||
var valValue = value[index];
|
|
||||||
if (isWhere) {
|
|
||||||
var othIndex = othLength;
|
|
||||||
while (othIndex--) {
|
|
||||||
result = baseIsEqual(valValue, other[othIndex], customizer, isWhere, stackA, stackB);
|
|
||||||
if (result) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
var othValue = other[index];
|
|
||||||
result = customizer ? customizer(valValue, othValue, index) : undefined;
|
|
||||||
if (typeof result == 'undefined') {
|
|
||||||
result = baseIsEqual(valValue, othValue, customizer, isWhere, stackA, stackB);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!result) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var valProps = isErr ? ['message', 'name'] : keys(value),
|
var valProps = isErr ? ['message', 'name'] : keys(value),
|
||||||
othProps = isErr ? valProps : keys(other);
|
othProps = isErr ? valProps : keys(other);
|
||||||
|
|
||||||
@@ -2048,24 +1981,85 @@
|
|||||||
if (othIsArg) {
|
if (othIsArg) {
|
||||||
othProps.push('length');
|
othProps.push('length');
|
||||||
}
|
}
|
||||||
length = valProps.length;
|
valLength = valProps.length;
|
||||||
result = length == othProps.length;
|
othLength = othProps.length;
|
||||||
|
if (valLength != othLength && !isWhere) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
switch (valClass) {
|
||||||
|
case boolClass:
|
||||||
|
case dateClass:
|
||||||
|
// coerce dates and booleans to numbers, dates to milliseconds and booleans
|
||||||
|
// to `1` or `0` treating invalid dates coerced to `NaN` as not equal
|
||||||
|
return +value == +other;
|
||||||
|
|
||||||
if (result || isWhere) {
|
case numberClass:
|
||||||
while (++index < length) {
|
// treat `NaN` vs. `NaN` as equal
|
||||||
var key = valProps[index];
|
return (value != +value)
|
||||||
result = isErr || hasOwnProperty.call(other, key);
|
? other != +other
|
||||||
|
// but treat `-0` vs. `+0` as not equal
|
||||||
|
: (value == 0 ? (1 / value == 1 / other) : value == +other);
|
||||||
|
|
||||||
if (result) {
|
case regexpClass:
|
||||||
valValue = value[key];
|
case stringClass:
|
||||||
othValue = other[key];
|
// coerce regexes to strings (http://es5.github.io/#x15.10.6.4) and
|
||||||
result = customizer ? customizer(valValue, othValue, key) : undefined;
|
// treat strings primitives and string objects as equal
|
||||||
if (typeof result == 'undefined') {
|
return value == String(other);
|
||||||
result = baseIsEqual(valValue, othValue, customizer, isWhere, stackA, stackB);
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// assume cyclic structures are equal
|
||||||
|
// the algorithm for detecting cyclic structures is adapted from ES 5.1
|
||||||
|
// section 15.12.3, abstract operation `JO` (http://es5.github.io/#x15.12.3)
|
||||||
|
stackA || (stackA = []);
|
||||||
|
stackB || (stackB = []);
|
||||||
|
|
||||||
|
var index = stackA.length;
|
||||||
|
while (index--) {
|
||||||
|
if (stackA[index] == value) {
|
||||||
|
return stackB[index] == other;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add `value` and `other` to the stack of traversed objects
|
||||||
|
stackA.push(value);
|
||||||
|
stackB.push(other);
|
||||||
|
|
||||||
|
// recursively compare objects and arrays (susceptible to call stack limits)
|
||||||
|
result = true;
|
||||||
|
if (isArr) {
|
||||||
|
// deep compare the contents, ignoring non-numeric properties
|
||||||
|
while (result && ++index < valLength) {
|
||||||
|
var valValue = value[index];
|
||||||
|
if (isWhere) {
|
||||||
|
var othIndex = othLength;
|
||||||
|
while (othIndex--) {
|
||||||
|
result = baseIsEqual(valValue, other[othIndex], customizer, isWhere, stackA, stackB);
|
||||||
|
if (result) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!result) {
|
} else {
|
||||||
break;
|
var othValue = other[index];
|
||||||
|
result = customizer ? customizer(valValue, othValue, index) : undefined;
|
||||||
|
if (typeof result == 'undefined') {
|
||||||
|
result = baseIsEqual(valValue, othValue, customizer, isWhere, stackA, stackB);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
while (result && ++index < valLength) {
|
||||||
|
var key = valProps[index];
|
||||||
|
result = isErr || hasOwnProperty.call(other, key);
|
||||||
|
|
||||||
|
if (result) {
|
||||||
|
valValue = value[key];
|
||||||
|
othValue = other[key];
|
||||||
|
result = customizer ? customizer(valValue, othValue, key) : undefined;
|
||||||
|
if (typeof result == 'undefined') {
|
||||||
|
result = baseIsEqual(valValue, othValue, customizer, isWhere, stackA, stackB);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10663,7 +10663,7 @@
|
|||||||
deepEqual(actual, [collection[1]]);
|
deepEqual(actual, [collection[1]]);
|
||||||
|
|
||||||
actual = _.where(collection, { 'a': [] });
|
actual = _.where(collection, { 'a': [] });
|
||||||
deepEqual(actual, []);
|
deepEqual(actual, collection);
|
||||||
|
|
||||||
actual = _.where(collection, { 'a': ['b', 'd'] });
|
actual = _.where(collection, { 'a': ['b', 'd'] });
|
||||||
deepEqual(actual, []);
|
deepEqual(actual, []);
|
||||||
|
|||||||
Reference in New Issue
Block a user