diff --git a/lodash.js b/lodash.js index 2cf114de7..d29362905 100644 --- a/lodash.js +++ b/lodash.js @@ -631,6 +631,25 @@ } } + /** + * Gets the index at which the first occurrence of `key` is found in `array` + * of key-value pairs. + * + * @private + * @param {Array} array The array to search. + * @param {*} key The key to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function assocIndexOf(array, key) { + var length = array.length; + while (length--) { + if (array[length][0] === key) { + return length; + } + } + return -1; + } + /** * The base implementation of methods like `_.find` and `_.findKey` without * support for callback shorthands, which iterates over `collection` using @@ -1337,8 +1356,9 @@ /** Native value references. */ var ArrayBuffer = context.ArrayBuffer, - Symbol = context.Symbol, + Map = getNative(context, 'Map'), Reflect = context.Reflect, + Symbol = context.Symbol, Uint8Array = context.Uint8Array, WeakMap = getNative(context, 'WeakMap'), clearTimeout = context.clearTimeout, @@ -1358,7 +1378,6 @@ nativeFloor = Math.floor, nativeIsFinite = context.isFinite, nativeKeys = Object.keys, - nativeMap = getNative(context, 'Map'), nativeMax = Math.max, nativeMin = Math.min, nativeParseInt = context.parseInt, @@ -1369,12 +1388,12 @@ var metaMap = WeakMap && new WeakMap; /** Used to detect maps and sets. */ - var mapCtorString = nativeMap ? fnToString.call(nativeMap) : '', + var mapCtorString = Map ? fnToString.call(Map) : '', setCtorString = nativeSet ? fnToString.call(nativeSet) : ''; /** Detect lack of support for map and set `toStringTag` values (IE 11). */ - var noMapSetTag = nativeMap && nativeSet && - !(objToString.call(new Map) == mapTag && objToString.call(new Set) == setTag); + var noMapSetTag = Map && nativeSet && + !(objToString.call(new Map) == mapTag && objToString.call(new nativeSet) == setTag); /** Used to lookup unminified function names. */ var realNames = {}; @@ -1699,19 +1718,19 @@ /*------------------------------------------------------------------------*/ /** - * Creates a cache object to store key/value pairs. + * Creates a memoize cache object to store key-value pairs. * * @private * @static * @name Cache * @memberOf _.memoize */ - function MapCache() { + function MemCache() { this.__data__ = {}; } /** - * Removes `key` and its value from the cache. + * Removes `key` and its value from the memoize cache. * * @private * @name delete @@ -1719,7 +1738,7 @@ * @param {string} key The key of the value to remove. * @returns {boolean} Returns `true` if the entry was removed successfully, else `false`. */ - function mapDelete(key) { + function memDelete(key) { return this.has(key) && delete this.__data__[key]; } @@ -1732,7 +1751,7 @@ * @param {string} key The key of the value to get. * @returns {*} Returns the cached value. */ - function mapGet(key) { + function memGet(key) { return key == '__proto__' ? undefined : this.__data__[key]; } @@ -1745,7 +1764,7 @@ * @param {string} key The key of the entry to check. * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. */ - function mapHas(key) { + function memHas(key) { return key != '__proto__' && hasOwnProperty.call(this.__data__, key); } @@ -1755,11 +1774,11 @@ * @private * @name set * @memberOf _.memoize.Cache - * @param {string} key The key of the value to cache. - * @param {*} value The value to cache. - * @returns {Object} Returns the cache object. + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the memoize cache object. */ - function mapSet(key, value) { + function memSet(key, value) { if (key != '__proto__') { this.__data__[key] = value; } @@ -1769,8 +1788,62 @@ /*------------------------------------------------------------------------*/ /** + * Creates a stack object to store key-value pairs. * - * Creates a cache object to store unique values. + * @private + */ + function Stack() { + return Map ? new Map : (this.__data__ = [], this); + } + + /** + * Removes `key` and its value from the stack. + * + * @private + * @name delete + * @memberOf Stack + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed successfully, else `false`. + */ + function stackDelete() { + var data = this.__data__; + return !!data.length && (data.pop(), true); + } + + /** + * Gets the stack value for `key`. + * + * @private + * @name get + * @memberOf Stack + * @param {string} key The key of the value to get. + * @returns {*} Returns the cached value. + */ + function stackGet(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + return index < 0 ? undefined : data[index][1]; + } + + /** + * Sets `value` to `key` of the stack. + * + * @private + * @name set + * @memberOf Stack + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + */ + function stackSet(key, value) { + this.__data__.push([key, value]); + } + + /*------------------------------------------------------------------------*/ + + /** + * + * Creates a set cache object to store unique values. * * @private * @param {Array} [values] The values to cache. @@ -1789,7 +1862,7 @@ * `_.indexOf` by returning `0` if the value is found, else `-1`. * * @private - * @param {Object} cache The cache to search. + * @param {Object} cache The set cache to search. * @param {*} value The value to search for. * @returns {number} Returns `0` if `value` is found, else `-1`. */ @@ -1801,7 +1874,7 @@ } /** - * Adds `value` to the cache. + * Adds `value` to the set cache. * * @private * @name push @@ -1862,14 +1935,13 @@ * @param {Function} [customizer] The function to customize cloning. * @param {string} [key] The key of `value`. * @param {Object} [object] The object `value` belongs to. - * @param {Array} [stackA=[]] Tracks traversed source objects. - * @param {Array} [stackB=[]] Associates clones with source counterparts. + * @param {Array} [stack] Tracks traversed sources and their clone counterparts. * @returns {*} Returns the cloned value. */ - function baseClone(value, isDeep, customizer, key, object, stackA, stackB) { + function baseClone(value, isDeep, customizer, key, object, stack) { var result; if (customizer) { - result = object ? customizer(value, key, object, stackA, stackB) : customizer(value); + result = object ? customizer(value, key, object, stack) : customizer(value); } if (result !== undefined) { return result; @@ -1905,22 +1977,16 @@ } } // Check for circular references and return its corresponding clone. - stackA || (stackA = []); - stackB || (stackB = []); - - var length = stackA.length; - while (length--) { - if (stackA[length] == value) { - return stackB[length]; - } + stack || (stack = new Stack); + var stacked = stack.get(value); + if (stacked) { + return stacked; } - // Add the source value to the stack of traversed objects and associate it with its clone. - stackA.push(value); - stackB.push(result); + stack.set(value, result); // Recursively populate clone (susceptible to call stack limits). (isArr ? arrayEach : baseForOwn)(value, function(subValue, key) { - result[key] = baseClone(subValue, isDeep, customizer, key, value, stackA, stackB); + result[key] = baseClone(subValue, isDeep, customizer, key, value, stack); }); return result; } @@ -2260,18 +2326,17 @@ * The bitmask may be composed of the following flags: * 1 - Unordered comparison * 2 - Partial comparison - * @param {Array} [stackA] Tracks traversed `value` objects. - * @param {Array} [stackB] Tracks traversed `other` objects. + * @param {Array} [stack] Tracks traversed `value` and `other` objects. * @returns {boolean} Returns `true` if the values are equivalent, else `false`. */ - function baseIsEqual(value, other, customizer, bitmask, stackA, stackB) { + function baseIsEqual(value, other, customizer, bitmask, stack) { if (value === other) { return true; } if (value == null || other == null || (!isObject(value) && !isObjectLike(other))) { return value !== value && other !== other; } - return baseIsEqualDeep(value, other, baseIsEqual, customizer, bitmask, stackA, stackB); + return baseIsEqualDeep(value, other, baseIsEqual, customizer, bitmask, stack); } /** @@ -2285,11 +2350,10 @@ * @param {Function} equalFunc The function to determine equivalents of values. * @param {Function} [customizer] The function to customize comparisons. * @param {number} [bitmask] The bitmask of comparison flags. See `baseIsEqual` for more details. - * @param {Array} [stackA=[]] Tracks traversed `value` objects. - * @param {Array} [stackB=[]] Tracks traversed `other` objects. + * @param {Array} [stack] Tracks traversed `value` and `other` objects. * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. */ - function baseIsEqualDeep(object, other, equalFunc, customizer, bitmask, stackA, stackB) { + function baseIsEqualDeep(object, other, equalFunc, customizer, bitmask, stack) { var objIsArr = isArray(object), othIsArr = isArray(other), objTag = arrayTag, @@ -2328,7 +2392,7 @@ othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); if (objIsWrapped || othIsWrapped) { - return equalFunc(objIsWrapped ? object.value() : object, othIsWrapped ? other.value() : other, customizer, bitmask, stackA, stackB); + return equalFunc(objIsWrapped ? object.value() : object, othIsWrapped ? other.value() : other, customizer, bitmask, stack); } } if (!isSameTag) { @@ -2336,24 +2400,16 @@ } // Assume cyclic values are equal. // For more information on detecting circular references see https://es5.github.io/#JO. - stackA || (stackA = []); - stackB || (stackB = []); - - var length = stackA.length; - while (length--) { - if (stackA[length] == object) { - return stackB[length] == other; - } + stack || (stack = new Stack); + var stacked = stack.get(object); + if (stacked) { + return stacked == other; } - // Add `object` and `other` to the stack of traversed objects. - stackA.push(object); - stackB.push(other); + stack.set(object, other); - var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, bitmask, stackA, stackB); - - stackA.pop(); - stackB.pop(); + var result = (objIsArr ? equalArrays : equalObjects)(object, other, equalFunc, customizer, bitmask, stack); + stack['delete'](object); return result; } @@ -2396,11 +2452,10 @@ return false; } } else { - var stackA = [], - stackB = [], - result = customizer ? customizer(objValue, srcValue, key, object, source, stackA, stackB) : undefined; + var stack = new Stack, + result = customizer ? customizer(objValue, srcValue, key, object, source, stack) : undefined; - if (!(result === undefined ? baseIsEqual(srcValue, objValue, customizer, UNORDERED_COMPARE_FLAG | PARTIAL_COMPARE_FLAG, stackA, stackB) : result)) { + if (!(result === undefined ? baseIsEqual(srcValue, objValue, customizer, UNORDERED_COMPARE_FLAG | PARTIAL_COMPARE_FLAG, stack) : result)) { return false; } } @@ -2537,10 +2592,9 @@ * @param {Object} object The destination object. * @param {Object} source The source object. * @param {Function} [customizer] The function to customize merged values. - * @param {Array} [stackA=[]] Tracks traversed source objects. - * @param {Array} [stackB=[]] Associates values with source counterparts. + * @param {Array} [stack] Tracks traversed sources and their value counterparts. */ - function baseMerge(object, source, customizer, stackA, stackB) { + function baseMerge(object, source, customizer, stack) { if (object === source) { return; } @@ -2551,12 +2605,11 @@ srcValue = source[key]; } if (isObject(srcValue)) { - stackA || (stackA = []); - stackB || (stackB = []); - baseMergeDeep(object, source, key, baseMerge, customizer, stackA, stackB); + stack || (stack = new Stack); + baseMergeDeep(object, source, key, baseMerge, customizer, stack); } else { - var newValue = customizer ? customizer(object[key], srcValue, (key + ''), object, source, stackA, stackB) : undefined; + var newValue = customizer ? customizer(object[key], srcValue, (key + ''), object, source, stack) : undefined; if (newValue === undefined) { newValue = srcValue; } @@ -2576,22 +2629,18 @@ * @param {string} key The key of the value to merge. * @param {Function} mergeFunc The function to merge values. * @param {Function} [customizer] The function to customize assigned values. - * @param {Array} [stackA=[]] Tracks traversed source objects. - * @param {Array} [stackB=[]] Associates values with source counterparts. + * @param {Array} [stack] Tracks traversed sources and their value counterparts. */ - function baseMergeDeep(object, source, key, mergeFunc, customizer, stackA, stackB) { - var length = stackA.length, - oldValue = object[key], - srcValue = source[key]; + function baseMergeDeep(object, source, key, mergeFunc, customizer, stack) { + var oldValue = object[key], + srcValue = source[key], + stacked = stack.get(oldValue) || stack.get(srcValue); - while (length--) { - var stacked = stackA[length]; - if (stacked == srcValue || stacked == oldValue) { - assignMergeValue(object, key, stackB[length]); - return; - } + if (stacked) { + assignMergeValue(object, key, stacked); + return; } - var newValue = customizer ? customizer(oldValue, srcValue, (key + ''), object, source, stackA, stackB) : undefined, + var newValue = customizer ? customizer(oldValue, srcValue, (key + ''), object, source, stack) : undefined, isCommon = newValue === undefined; if (isCommon) { @@ -2610,14 +2659,11 @@ isCommon = isFunction(srcValue); } } - // Add the source value to the stack of traversed objects and associate - // it with its merged value. - stackA.push(srcValue); - stackB.push(newValue); + stack.set(srcValue, newValue); if (isCommon) { // Recursively merge objects and arrays (susceptible to call stack limits). - mergeFunc(newValue, srcValue, customizer, stackA, stackB); + mergeFunc(newValue, srcValue, customizer, stack); } assignMergeValue(object, key, newValue); } @@ -3793,11 +3839,10 @@ * @param {Function} equalFunc The function to determine equivalents of values. * @param {Function} [customizer] The function to customize comparisons. * @param {number} [bitmask] The bitmask of comparison flags. See `baseIsEqual` for more details. - * @param {Array} [stackA] Tracks traversed `value` objects. - * @param {Array} [stackB] Tracks traversed `other` objects. + * @param {Array} [stack] Tracks traversed `value` and `other` objects. * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. */ - function equalArrays(array, other, equalFunc, customizer, bitmask, stackA, stackB) { + function equalArrays(array, other, equalFunc, customizer, bitmask, stack) { var index = -1, isPartial = bitmask & PARTIAL_COMPARE_FLAG, isUnordered = bitmask & UNORDERED_COMPARE_FLAG, @@ -3814,8 +3859,8 @@ if (customizer) { var result = isPartial - ? customizer(othValue, arrValue, index, other, array, stackA, stackB) - : customizer(arrValue, othValue, index, array, other, stackA, stackB); + ? customizer(othValue, arrValue, index, other, array, stack) + : customizer(arrValue, othValue, index, array, other, stack); } if (result !== undefined) { if (result) { @@ -3826,11 +3871,11 @@ // Recursively compare arrays (susceptible to call stack limits). if (isUnordered) { if (!arraySome(other, function(othValue) { - return arrValue === othValue || equalFunc(arrValue, othValue, customizer, bitmask, stackA, stackB); + return arrValue === othValue || equalFunc(arrValue, othValue, customizer, bitmask, stack); })) { return false; } - } else if (!(arrValue === othValue || equalFunc(arrValue, othValue, customizer, bitmask, stackA, stackB))) { + } else if (!(arrValue === othValue || equalFunc(arrValue, othValue, customizer, bitmask, stack))) { return false; } } @@ -3900,11 +3945,10 @@ * @param {Function} equalFunc The function to determine equivalents of values. * @param {Function} [customizer] The function to customize comparisons. * @param {number} [bitmask] The bitmask of comparison flags. See `baseIsEqual` for more details. - * @param {Array} [stackA] Tracks traversed `value` objects. - * @param {Array} [stackB] Tracks traversed `other` objects. + * @param {Array} [stack] Tracks traversed `value` and `other` objects. * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. */ - function equalObjects(object, other, equalFunc, customizer, bitmask, stackA, stackB) { + function equalObjects(object, other, equalFunc, customizer, bitmask, stack) { var isPartial = bitmask & PARTIAL_COMPARE_FLAG, isUnordered = bitmask & UNORDERED_COMPARE_FLAG, objProps = keys(object), @@ -3931,12 +3975,12 @@ if (customizer) { var result = isPartial - ? customizer(othValue, objValue, key, other, object, stackA, stackB) - : customizer(objValue, othValue, key, object, other, stackA, stackB); + ? customizer(othValue, objValue, key, other, object, stack) + : customizer(objValue, othValue, key, object, other, stack); } // Recursively compare objects (susceptible to call stack limits). if (!(result === undefined - ? (objValue === othValue || equalFunc(objValue, othValue, customizer, bitmask, stackA, stackB)) + ? (objValue === othValue || equalFunc(objValue, othValue, customizer, bitmask, stack)) : result )) { return false; @@ -4417,11 +4461,10 @@ * @param {*} srcValue The source object property value. * @returns {*} Returns the value to assign to the destination object. */ - function mergeDefaults(objValue, srcValue, key, object, source, stackA, stackB) { + function mergeDefaults(objValue, srcValue, key, object, source, stack) { if (isObject(objValue)) { - stackA.push(objValue); - stackB.push(objValue); - baseMerge(objValue, srcValue, mergeDefaults, stackA, stackB); + stack.set(objValue, objValue); + baseMerge(objValue, srcValue, mergeDefaults, stack); } return objValue === undefined ? srcValue : objValue; } @@ -8207,7 +8250,7 @@ * This method is like `_.clone` except that it accepts `customizer` which * is invoked to produce the cloned value. If `customizer` returns `undefined` * cloning is handled by the method instead. The `customizer` is invoked with - * up to five arguments; (value [, index|key, object, stackA, stackB]). + * up to five arguments; (value [, index|key, object, stack]). * * @static * @memberOf _ @@ -8563,7 +8606,7 @@ * This method is like `_.isEqual` except that it accepts `customizer` which is * invoked to compare values. If `customizer` returns `undefined` comparisons are * handled by the method instead. The `customizer` is invoked with up to seven arguments: - * (objValue, othValue [, index|key, object, other, stackA, stackB]). + * (objValue, othValue [, index|key, object, other, stack]). * * @static * @memberOf _ @@ -9973,7 +10016,7 @@ * is invoked to produce the merged values of the destination and source * properties. If `customizer` returns `undefined` merging is handled by the * method instead. The `customizer` is invoked with seven arguments: - * (objValue, srcValue, key, object, source, stackA, stackB). + * (objValue, srcValue, key, object, source, stack). * * @static * @memberOf _ @@ -10057,7 +10100,7 @@ } /** - * Creates a two dimensional array of the key-value pairs for `object`, + * Creates an array of the key-value pairs for `object`, * e.g. `[[key1, value1], [key2, value2]]`. * * @static @@ -12115,17 +12158,22 @@ LazyWrapper.prototype = baseCreate(baseLodash.prototype); LazyWrapper.prototype.constructor = LazyWrapper; - // Add functions to the `Map` cache. - MapCache.prototype['delete'] = mapDelete; - MapCache.prototype.get = mapGet; - MapCache.prototype.has = mapHas; - MapCache.prototype.set = mapSet; + // Add functions to the `MemCache` cache. + MemCache.prototype['delete'] = memDelete; + MemCache.prototype.get = memGet; + MemCache.prototype.has = memHas; + MemCache.prototype.set = memSet; // Add functions to the `Set` cache. SetCache.prototype.push = cachePush; + // Add functions to the `Stack` cache. + Stack.prototype['delete'] = stackDelete; + Stack.prototype.get = stackGet; + Stack.prototype.set = stackSet; + // Assign cache to `_.memoize`. - memoize.Cache = MapCache; + memoize.Cache = MemCache; // Add functions that return wrapped values when chaining. lodash.after = after; diff --git a/test/test.js b/test/test.js index 7f937f428..fdde09bd1 100644 --- a/test/test.js +++ b/test/test.js @@ -2259,10 +2259,13 @@ foo = new Foo; func(foo, function() { - argsList.push(slice.call(arguments)); + var length = arguments.length, + args = slice.call(arguments, 0, length - (length > 1 ? 1 : 0)); + + argsList.push(args); }); - assert.deepEqual(argsList, isDeepWith ? [[foo], [1, 'a', foo, [foo], [{ 'a': 1 }]]] : [[foo]]); + assert.deepEqual(argsList, isDeepWith ? [[foo], [1, 'a', foo]] : [[foo]]); }); QUnit.test('`_.' + methodName + '` should handle cloning if `customizer` returns `undefined`', function(assert) { @@ -6025,11 +6028,8 @@ source = { 'a': 2 }, expected = _.map([1, 2, 'a', object, source], _.clone); - if (isMergeWith) { - expected.push(undefined, undefined); - } func(object, source, function() { - args || (args = _.map(arguments, _.clone)); + args || (args = _.map(slice.call(arguments, 0, 5), _.clone)); }); assert.deepEqual(args, expected, 'primitive property values'); @@ -6039,11 +6039,8 @@ source = { 'b': 2 }; expected = _.map([undefined, 2, 'b', object, source], _.clone); - if (isMergeWith) { - expected.push(undefined, undefined); - } func(object, source, function() { - args || (args = _.map(arguments, _.clone)); + args || (args = _.map(slice.call(arguments, 0, 5), _.clone)); }); assert.deepEqual(args, expected, 'missing destination property'); @@ -6057,11 +6054,10 @@ expected = [_.map([objectValue, sourceValue, 'a', object, source], _.cloneDeep)]; if (isMergeWith) { - expected[0].push([], []); - expected.push(_.map([undefined, 2, 'b', objectValue, sourceValue, [sourceValue], [objectValue]], _.cloneDeep)); + expected.push(_.map([undefined, 2, 'b', objectValue, sourceValue], _.cloneDeep)); } func(object, source, function() { - argsList.push(_.map(arguments, _.cloneDeep)); + argsList.push(_.map(slice.call(arguments, 0, 5), _.cloneDeep)); }); assert.deepEqual(argsList, expected, 'object property values'); @@ -8273,18 +8269,21 @@ var expected = [ [object1, object2], - [object1.a, object2.a, 'a', object1, object2, [], []], - [object1.a[0], object2.a[0], 0, object1.a, object2.a, [], []], - [object1.a[1], object2.a[1], 1, object1.a, object2.a, [], []], - [object1.b, object2.b, 'b', object1.b, object2.b, [], []], - [object1.b.a, object2.b.a, 'a', object1.b, object2.b, [], []], - [object1.b.a[0], object2.b.a[0], 0, object1.b.a, object2.b.a, [], []], - [object1.b.a[1], object2.b.a[1], 1, object1.b.a, object2.b.a, [], []], - [object1.b.b, object2.b.b, 'b', object1.b.b, object2.b.b, [], []] + [object1.a, object2.a, 'a', object1, object2], + [object1.a[0], object2.a[0], 0, object1.a, object2.a], + [object1.a[1], object2.a[1], 1, object1.a, object2.a], + [object1.b, object2.b, 'b', object1.b, object2.b], + [object1.b.a, object2.b.a, 'a', object1.b, object2.b], + [object1.b.a[0], object2.b.a[0], 0, object1.b.a, object2.b.a], + [object1.b.a[1], object2.b.a[1], 1, object1.b.a, object2.b.a], + [object1.b.b, object2.b.b, 'b', object1.b.b, object2.b.b] ]; _.isEqualWith(object1, object2, function(assert) { - argsList.push(slice.call(arguments)); + var length = arguments.length, + args = slice.call(arguments, 0, length - (length > 2 ? 1 : 0)); + + argsList.push(args); }); assert.deepEqual(argsList, expected); @@ -8375,16 +8374,19 @@ var expected = [ [pair[0], pair[1]], - [array[0], array[0], 0, array, array, [], []], - [array[0][0], array[0][0], 0, array[0], array[0], [], []], - [array[0][1], array[0][1], 1, array[0], array[0], [], []] + [array[0], array[0], 0, array, array], + [array[0][0], array[0][0], 0, array[0], array[0]], + [array[0][1], array[0][1], 1, array[0], array[0]] ]; if (index) { expected.length = 2; } _.isEqualWith(pair[0], pair[1], function() { - argsList.push(slice.call(arguments)); + var length = arguments.length, + args = slice.call(arguments, 0, length - (length > 2 ? 1 : 0)); + + argsList.push(args); }); assert.deepEqual(argsList, expected, index ? 'Set' : 'Map'); @@ -9007,22 +9009,22 @@ object2.b = object1; var expected = [ - [object1.a, object2.a, 'a', object1, object2, [], []], - [object1.a[0], object2.a[0], 0, object1.a, object2.a, [], []], - [object1.a[1], object2.a[1], 1, object1.a, object2.a, [], []], - [object1.b, object2.b, 'b', object1, object2, [], []], - [object1.b.a, object2.b.a, 'a', object1.b, object2.b, [], []], - [object1.b.a[0], object2.b.a[0], 0, object1.b.a, object2.b.a, [], []], - [object1.b.a[1], object2.b.a[1], 1, object1.b.a, object2.b.a, [], []], - [object1.b.b, object2.b.b, 'b', object1.b, object2.b, [], []], - [object1.b.b.a, object2.b.b.a, 'a', object1.b.b, object2.b.b, [], []], - [object1.b.b.a[0], object2.b.b.a[0], 0, object1.b.b.a, object2.b.b.a, [], []], - [object1.b.b.a[1], object2.b.b.a[1], 1, object1.b.b.a, object2.b.b.a, [], []], - [object1.b.b.b, object2.b.b.b, 'b', object1.b.b, object2.b.b, [], []] + [object1.a, object2.a, 'a', object1, object2], + [object1.a[0], object2.a[0], 0, object1.a, object2.a], + [object1.a[1], object2.a[1], 1, object1.a, object2.a], + [object1.b, object2.b, 'b', object1, object2], + [object1.b.a, object2.b.a, 'a', object1.b, object2.b], + [object1.b.a[0], object2.b.a[0], 0, object1.b.a, object2.b.a], + [object1.b.a[1], object2.b.a[1], 1, object1.b.a, object2.b.a], + [object1.b.b, object2.b.b, 'b', object1.b, object2.b], + [object1.b.b.a, object2.b.b.a, 'a', object1.b.b, object2.b.b], + [object1.b.b.a[0], object2.b.b.a[0], 0, object1.b.b.a, object2.b.b.a], + [object1.b.b.a[1], object2.b.b.a[1], 1, object1.b.b.a, object2.b.b.a], + [object1.b.b.b, object2.b.b.b, 'b', object1.b.b, object2.b.b] ]; _.isMatchWith(object1, object2, function(assert) { - argsList.push(slice.call(arguments)); + argsList.push(slice.call(arguments, 0, -1)); }); assert.deepEqual(argsList, expected); @@ -9111,17 +9113,17 @@ object2 = { 'a': pair[1] }; var expected = [ - [pair[0], pair[1], 'a', object1, object2, [], []], - [array[0], array[0], 0, array, array, [], []], - [array[0][0], array[0][0], 0, array[0], array[0], [], []], - [array[0][1], array[0][1], 1, array[0], array[0], [], []] + [pair[0], pair[1], 'a', object1, object2], + [array[0], array[0], 0, array, array], + [array[0][0], array[0][0], 0, array[0], array[0]], + [array[0][1], array[0][1], 1, array[0], array[0]] ]; if (index) { expected.length = 2; } _.isMatchWith({ 'a': pair[0] }, { 'a': pair[1] }, function() { - argsList.push(slice.call(arguments)); + argsList.push(slice.call(arguments, 0, -1)); }); assert.deepEqual(argsList, expected, index ? 'Set' : 'Map'); @@ -13091,7 +13093,7 @@ return new Wrapper(value); } if (_.has(value, '__wrapped__')) { - var actions = _.slice(value.__actions__), + var actions = slice.call(value.__actions__), chain = value.__chain__; value = value.__wrapped__;