mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-02-07 18:07:49 +00:00
Ensure _.where works correctly for nested properties and give indicator arguments more meaningful names.
Former-commit-id: c35e2817125cd852a66066ccdef44bcc40c93e61
This commit is contained in:
74
lodash.js
74
lodash.js
@@ -556,10 +556,10 @@
|
||||
* @param {Function|String} func The function to bind or the method name.
|
||||
* @param {Mixed} [thisArg] The `this` binding of `func`.
|
||||
* @param {Array} partialArgs An array of arguments to be partially applied.
|
||||
* @param {Object} [right] Used to indicate partially applying arguments from the right.
|
||||
* @param {Object} [rightIndicator] Used to indicate partially applying arguments from the right.
|
||||
* @returns {Function} Returns the new bound function.
|
||||
*/
|
||||
function createBound(func, thisArg, partialArgs, right) {
|
||||
function createBound(func, thisArg, partialArgs, rightIndicator) {
|
||||
var isFunc = isFunction(func),
|
||||
isPartial = !partialArgs,
|
||||
key = thisArg;
|
||||
@@ -583,7 +583,7 @@
|
||||
}
|
||||
if (partialArgs.length) {
|
||||
args = args.length
|
||||
? (args = slice(args), right ? args.concat(partialArgs) : partialArgs.concat(args))
|
||||
? (args = slice(args), rightIndicator ? args.concat(partialArgs) : partialArgs.concat(args))
|
||||
: partialArgs;
|
||||
}
|
||||
if (this instanceof bound) {
|
||||
@@ -630,7 +630,7 @@
|
||||
var length = props.length,
|
||||
result = false;
|
||||
while (length--) {
|
||||
if (!(result = isEqual(object[props[length]], func[props[length]]))) {
|
||||
if (!(result = isEqual(object[props[length]], func[props[length]], indicatorObject))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1031,10 +1031,9 @@
|
||||
* @memberOf _
|
||||
* @category Objects
|
||||
* @param {Mixed} value The value to clone.
|
||||
* @param- {Object} [deep] Internally used to indicate performing a deep clone.
|
||||
* @param- {Object} [deepIndicator] Internally used to indicate performing a deep clone.
|
||||
* @param- {Array} [stackA=[]] Internally used to track traversed source objects.
|
||||
* @param- {Array} [stackB=[]] Internally used to associate clones with their
|
||||
* source counterparts.
|
||||
* @param- {Array} [stackB=[]] Internally used to associate clones with their source counterparts.
|
||||
* @returns {Mixed} Returns the cloned `value`.
|
||||
* @example
|
||||
*
|
||||
@@ -1050,10 +1049,10 @@
|
||||
* shallow == stooges;
|
||||
* // => false
|
||||
*/
|
||||
function clone(value, deep, stackA, stackB) {
|
||||
function clone(value, deepIndicator, stackA, stackB) {
|
||||
// allows working with "Collections" methods without using their `callback`
|
||||
// arguments, `index|key` and `collection`
|
||||
deep = deep == indicatorObject;
|
||||
deepIndicator = deepIndicator == indicatorObject;
|
||||
|
||||
// inspect [[Class]]
|
||||
var isObj = isObject(value);
|
||||
@@ -1065,7 +1064,7 @@
|
||||
var isArr = isArray(value);
|
||||
}
|
||||
// shallow clone
|
||||
if (!isObj || !deep) {
|
||||
if (!isObj || !deepIndicator) {
|
||||
return isObj
|
||||
? (isArr ? slice(value) : assign({}, value))
|
||||
: value;
|
||||
@@ -1340,6 +1339,8 @@
|
||||
* @category Objects
|
||||
* @param {Mixed} a The value to compare.
|
||||
* @param {Mixed} b The other value to compare.
|
||||
* @param- {Object} [whereIndicator] Internally used to indicate that when
|
||||
* comparing objects, `a` has at least the properties of `b`.
|
||||
* @param- {Object} [stackA=[]] Internally used track traversed `a` objects.
|
||||
* @param- {Object} [stackB=[]] Internally used track traversed `b` objects.
|
||||
* @returns {Boolean} Returns `true`, if the values are equvalent, else `false`.
|
||||
@@ -1354,27 +1355,32 @@
|
||||
* _.isEqual(moe, clone);
|
||||
* // => true
|
||||
*/
|
||||
function isEqual(a, b, stackA, stackB) {
|
||||
function isEqual(a, b, whereIndicator, stackA, stackB) {
|
||||
// exit early for identical values
|
||||
if (a === b) {
|
||||
// treat `+0` vs. `-0` as not equal
|
||||
return a !== 0 || (1 / a == 1 / b);
|
||||
}
|
||||
// exit early for unlike `null` or `undefined` values
|
||||
if (a == null || b == null) {
|
||||
var type = typeof a,
|
||||
otherType = typeof b;
|
||||
|
||||
// exit early for unlike primitive values
|
||||
if (a === a &&
|
||||
(!a || (type != 'function' && type != 'object')) &&
|
||||
(!b || (otherType != 'function' && otherType != 'object'))) {
|
||||
return false;
|
||||
}
|
||||
// compare [[Class]] names
|
||||
var className = toString.call(a),
|
||||
otherName = toString.call(b);
|
||||
otherClass = toString.call(b);
|
||||
|
||||
if (className == argsClass) {
|
||||
className = objectClass;
|
||||
}
|
||||
if (otherName == argsClass) {
|
||||
otherName = objectClass;
|
||||
if (otherClass == argsClass) {
|
||||
otherClass = objectClass;
|
||||
}
|
||||
if (className != otherName) {
|
||||
if (className != otherClass) {
|
||||
return false;
|
||||
}
|
||||
switch (className) {
|
||||
@@ -1401,7 +1407,7 @@
|
||||
if (!isArr) {
|
||||
// unwrap any `lodash` wrapped values
|
||||
if (a.__wrapped__ || b.__wrapped__) {
|
||||
return isEqual(a.__wrapped__ || a, b.__wrapped__ || b);
|
||||
return isEqual(a.__wrapped__ || a, b.__wrapped__ || b, whereIndicator);
|
||||
}
|
||||
// exit for functions and DOM nodes
|
||||
if (className != objectClass || (noNodeClass && (isNode(a) || isNode(b)))) {
|
||||
@@ -1441,13 +1447,13 @@
|
||||
// recursively compare objects and arrays (susceptible to call stack limits)
|
||||
if (isArr) {
|
||||
// compare lengths to determine if a deep comparison is necessary
|
||||
size = a.length;
|
||||
result = size == b.length;
|
||||
size = b.length;
|
||||
result = whereIndicator == indicatorObject || size == a.length;
|
||||
|
||||
if (result) {
|
||||
// deep compare the contents, ignoring non-numeric properties
|
||||
while (size--) {
|
||||
if (!(result = isEqual(a[size], b[size], stackA, stackB))) {
|
||||
if (!(result = isEqual(a[size], b[size], whereIndicator, stackA, stackB))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1456,20 +1462,20 @@
|
||||
}
|
||||
// deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys`
|
||||
// which, in this case, is more costly
|
||||
forIn(a, function(value, key, a) {
|
||||
if (hasOwnProperty.call(a, key)) {
|
||||
forIn(b, function(value, key, b) {
|
||||
if (hasOwnProperty.call(b, key)) {
|
||||
// count the number of properties.
|
||||
size++;
|
||||
// deep compare each property value.
|
||||
return (result = hasOwnProperty.call(b, key) && isEqual(value, b[key], stackA, stackB));
|
||||
return (result = hasOwnProperty.call(a, key) && isEqual(a[key], value, whereIndicator, stackA, stackB));
|
||||
}
|
||||
});
|
||||
|
||||
if (result) {
|
||||
if (result && whereIndicator != indicatorObject) {
|
||||
// ensure both objects have the same number of properties
|
||||
forIn(b, function(value, key, b) {
|
||||
if (hasOwnProperty.call(b, key)) {
|
||||
// `size` will be `-1` if `b` has more properties than `a`
|
||||
forIn(a, function(value, key, a) {
|
||||
if (hasOwnProperty.call(a, key)) {
|
||||
// `size` will be `-1` if `a` has more properties than `b`
|
||||
return (result = --size > -1);
|
||||
}
|
||||
});
|
||||
@@ -1730,8 +1736,8 @@
|
||||
* @param {Object} [source1, source2, ...] The source objects.
|
||||
* @param {Function} [callback] The function called for each property to merge.
|
||||
* @param {Mixed} [thisArg] The `this` binding of `callback`.
|
||||
* @param- {Object} [indicator] Internally used to indicate that the `stack`
|
||||
* argument is an array of traversed objects instead of another source object.
|
||||
* @param- {Object} [deepIndicator] Internally used to indicate that `stackA`
|
||||
* and `stackB` are arrays of traversed objects instead of source objects.
|
||||
* @param- {Array} [stackA=[]] Internally used to track traversed source objects.
|
||||
* @param- {Array} [stackB=[]] Internally used to associate values with their
|
||||
* source counterparts.
|
||||
@@ -1755,7 +1761,7 @@
|
||||
* _.merge(names, ages);
|
||||
* // => { 'stooges': [{ 'name': 'moe', 'age': 40 }, { 'name': 'larry', 'age': 50 }] }
|
||||
*/
|
||||
function merge(object, source, indicator) {
|
||||
function merge(object, source, deepIndicator) {
|
||||
var args = arguments,
|
||||
index = 0,
|
||||
length = 2;
|
||||
@@ -1763,7 +1769,7 @@
|
||||
if (!isObject(object)) {
|
||||
return object;
|
||||
}
|
||||
if (indicator === indicatorObject) {
|
||||
if (deepIndicator === indicatorObject) {
|
||||
var callback = args[3],
|
||||
stackA = args[4],
|
||||
stackB = args[5];
|
||||
@@ -1774,7 +1780,7 @@
|
||||
|
||||
// allows working with `_.reduce` and `_.reduceRight` without
|
||||
// using their `callback` arguments, `index|key` and `collection`
|
||||
if (typeof indicator != 'number') {
|
||||
if (typeof deepIndicator != 'number') {
|
||||
length = args.length;
|
||||
callback = typeof (callback = args[length - 2]) == 'function'
|
||||
? createCallback(callback, args[--length])
|
||||
@@ -2766,7 +2772,7 @@
|
||||
|
||||
/**
|
||||
* Examines each element in a `collection`, returning an array of all elements
|
||||
* that contain the given `properties`.
|
||||
* that have the given `properties`.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
|
||||
Reference in New Issue
Block a user