From 6a73b0820e37769384bc0d352b67ca67214cdd8c Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sat, 6 Jul 2013 13:48:27 -0700 Subject: [PATCH] Ensure `_.flatten` will flatten `arguments` objects. Former-commit-id: 9ea8e40ff85b217a6497c9bbf91c9640211d9477 --- lodash.js | 150 +++++++++++++++++++++++++++++---------------------- test/test.js | 10 +++- 2 files changed, 95 insertions(+), 65 deletions(-) diff --git a/lodash.js b/lodash.js index 0baf9b311..42bf87bfb 100644 --- a/lodash.js +++ b/lodash.js @@ -975,6 +975,88 @@ /*--------------------------------------------------------------------------*/ + /** + * A basic implementation of `_.flatten` without support for `callback` + * shorthands or `thisArg` binding. + * + * @private + * @param {Array} array The array to flatten. + * @param {Boolean} [isShallow=false] A flag to indicate only flattening a single level. + * @param {Function} [callback] The function called per iteration. + * @returns {Array} Returns a new flattened array. + */ + function basicFlatten(array, isShallow, callback) { + var index = -1, + length = array ? array.length : 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (callback) { + value = callback(value, index, array); + } + // recursively flatten arrays (susceptible to call stack limits) + if (value && typeof value == 'object' && (isArray(value) || isArguments(value))) { + push.apply(result, isShallow ? value : basicFlatten(value)); + } else { + result.push(value); + } + } + return result; + } + + /** + * A basic implementation of `_.uniq` without support for `callback` shorthands + * or `thisArg` binding. + * + * @private + * @param {Array} array The array to process. + * @param {Boolean} [isSorted=false] A flag to indicate that the `array` is already sorted. + * @param {Function} [callback] The function called per iteration. + * @returns {Array} Returns a duplicate-value-free array. + */ + function basicUniq(array, isSorted, callback) { + var index = -1, + indexOf = getIndexOf(), + length = array ? array.length : 0, + result = []; + + var isLarge = !isSorted && length >= largeArraySize && indexOf === basicIndexOf, + seen = (callback || isLarge) ? getArray() : result; + + if (isLarge) { + var cache = createCache(seen); + if (cache) { + indexOf = cacheIndexOf; + seen = cache; + } else { + isLarge = false; + seen = callback ? seen : (releaseArray(seen), result); + } + } + while (++index < length) { + var value = array[index], + computed = callback ? callback(value, index, array) : value; + + if (isSorted + ? !index || seen[seen.length - 1] !== computed + : indexOf(seen, computed) < 0 + ) { + if (callback || isLarge) { + seen.push(computed); + } + result.push(value); + } + } + if (isLarge) { + releaseArray(seen.array); + releaseObject(seen); + } else if (callback) { + releaseArray(seen); + } + return result; + } + /** * Creates a function that, when called, invokes `func` with the `this` binding * of `thisArg` and prepends any `partialArgs` to the arguments passed to the @@ -3850,25 +3932,7 @@ * _.flatten(stooges, 'quotes'); * // => ['Oh, a wise guy, eh?', 'Poifect!', 'Spread out!', 'You knucklehead!'] */ - var flatten = overloadWrapper(function flatten(array, isShallow, callback) { - var index = -1, - length = array ? array.length : 0, - result = []; - - while (++index < length) { - var value = array[index]; - if (callback) { - value = callback(value, index, array); - } - // recursively flatten arrays (susceptible to call stack limits) - if (isArray(value)) { - push.apply(result, isShallow ? value : flatten(value)); - } else { - result.push(value); - } - } - return result; - }); + var flatten = overloadWrapper(basicFlatten); /** * Gets the index at which the first occurrence of `value` is found using @@ -4355,10 +4419,10 @@ * // => [1, 2, 3, 101, 10] */ function union(array) { - if (!isArray(array)) { - arguments[0] = array ? nativeSlice.call(array) : arrayRef; + if (!array) { + arguments[0] = arrayRef; } - return uniq(concat.apply(arrayRef, arguments)); + return basicUniq(basicFlatten(arguments, true)); } /** @@ -4404,47 +4468,7 @@ * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); * // => [{ 'x': 1 }, { 'x': 2 }] */ - var uniq = overloadWrapper(function(array, isSorted, callback) { - var index = -1, - indexOf = getIndexOf(), - length = array ? array.length : 0, - result = []; - - var isLarge = !isSorted && length >= largeArraySize && indexOf === basicIndexOf, - seen = (callback || isLarge) ? getArray() : result; - - if (isLarge) { - var cache = createCache(seen); - if (cache) { - indexOf = cacheIndexOf; - seen = cache; - } else { - isLarge = false; - seen = callback ? seen : (releaseArray(seen), result); - } - } - while (++index < length) { - var value = array[index], - computed = callback ? callback(value, index, array) : value; - - if (isSorted - ? !index || seen[seen.length - 1] !== computed - : indexOf(seen, computed) < 0 - ) { - if (callback || isLarge) { - seen.push(computed); - } - result.push(value); - } - } - if (isLarge) { - releaseArray(seen.array); - releaseObject(seen); - } else if (callback) { - releaseArray(seen); - } - return result; - }); + var uniq = overloadWrapper(basicUniq); /** * The inverse of `_.zip`, this method splits groups of elements into arrays diff --git a/test/test.js b/test/test.js index c43c6093e..e7bf44c13 100644 --- a/test/test.js +++ b/test/test.js @@ -939,7 +939,13 @@ QUnit.module('lodash.flatten'); (function() { - var array = [{ 'a': [1, [2]] }, { 'a': [3] }]; + var args = arguments, + array = [{ 'a': [1, [2]] }, { 'a': [3] }]; + + test('should flatten `arguments` objects', function() { + var actual = _.flatten([args, args]); + deepEqual(actual, [1, 2, 3, 1, 2, 3]); + }); test('should work with a `callback`', function() { var actual = _.flatten(array, function(value) { @@ -1000,7 +1006,7 @@ deepEqual(actual2, expected); ok(4 in actual2); }); - }()); + }(1, 2, 3)); /*--------------------------------------------------------------------------*/