From 6dc543ca187651a4493b517691df83c7caf4bfdb Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Thu, 23 May 2013 20:23:10 -0700 Subject: [PATCH] Rename internal `each` to `basicEach` and add internal `overloadWrapper` function. Former-commit-id: b12ea9977ab7b6da877aca5925a9fc59019bec93 --- lodash.js | 298 +++++++++++++++++++++++++++++------------------------- 1 file changed, 158 insertions(+), 140 deletions(-) diff --git a/lodash.js b/lodash.js index 6de91505d..d34c622b3 100644 --- a/lodash.js +++ b/lodash.js @@ -658,80 +658,25 @@ /*--------------------------------------------------------------------------*/ /** - * Creates a function optimized to search large arrays for a given `value`, - * starting at `fromIndex`, using strict equality for comparisons, i.e. `===`. + * A basic version of `_.indexOf` without support for binary searches + * or `fromIndex` constraints. * * @private * @param {Array} array The array to search. * @param {Mixed} value The value to search for. - * @returns {Boolean} Returns `true`, if `value` is found, else `false`. + * @param {Number} [fromIndex=0] The index to search from. + * @returns {Number} Returns the index of the matched value or `-1`. */ - function createCache(array) { - var bailout, - index = -1, - length = array.length, - isLarge = length >= largeArraySize, - objCache = {}; + function basicIndexOf(array, value, fromIndex) { + var index = (fromIndex || 0) - 1, + length = array.length; - var caches = { - 'false': false, - 'function': false, - 'null': false, - 'number': {}, - 'object': objCache, - 'string': {}, - 'true': false, - 'undefined': false - }; - - function cacheContains(value) { - var type = typeof value; - if (type == 'boolean' || value == null) { - return caches[value]; - } - var cache = caches[type] || (type = 'object', objCache), - key = type == 'number' ? value : keyPrefix + value; - - return type == 'object' - ? (cache[key] ? indexOf(cache[key], value) > -1 : false) - : !!cache[key]; - } - - function cachePush(value) { - var type = typeof value; - if (type == 'boolean' || value == null) { - caches[value] = true; - } else { - var cache = caches[type] || (type = 'object', objCache), - key = type == 'number' ? value : keyPrefix + value; - - if (type == 'object') { - bailout = (cache[key] || (cache[key] = [])).push(value) == length; - } else { - cache[key] = true; - } + while (++index < length) { + if (array[index] === value) { + return index; } } - - function simpleContains(value) { - return indexOf(array, value) > -1; - } - - function simplePush(value) { - array.push(value); - } - - if (isLarge) { - while (++index < length) { - cachePush(array[index]); - } - if (bailout) { - isLarge = caches = objCache = null; - } - } - return isLarge - ? { 'contains': cacheContains, 'push': cachePush } - : { 'push': simplePush, 'contains' : simpleContains }; + return -1; } /** @@ -833,6 +778,86 @@ return bound; } + + /** + * Creates a function optimized to search large arrays for a given `value`, + * starting at `fromIndex`, using strict equality for comparisons, i.e. `===`. + * + * @private + * @param {Array} [array=[]] The array to search. + * @param {Mixed} value The value to search for. + * @returns {Boolean} Returns `true`, if `value` is found, else `false`. + */ + function createCache(array) { + array || (array = []); + + var bailout, + index = -1, + length = array.length, + isLarge = length >= largeArraySize, + objCache = {}; + + var caches = { + 'false': false, + 'function': false, + 'null': false, + 'number': {}, + 'object': objCache, + 'string': {}, + 'true': false, + 'undefined': false + }; + + function basicContains(value) { + return basicIndexOf(array, value) > -1; + } + + function basicPush(value) { + array.push(value); + } + + function cacheContains(value) { + var type = typeof value; + if (type == 'boolean' || value == null) { + return caches[value]; + } + var cache = caches[type] || (type = 'object', objCache), + key = type == 'number' ? value : keyPrefix + value; + + return type == 'object' + ? (cache[key] ? basicIndexOf(cache[key], value) > -1 : false) + : !!cache[key]; + } + + function cachePush(value) { + var type = typeof value; + if (type == 'boolean' || value == null) { + caches[value] = true; + } else { + var cache = caches[type] || (type = 'object', objCache), + key = type == 'number' ? value : keyPrefix + value; + + if (type == 'object') { + bailout = (cache[key] || (cache[key] = [])).push(value) == length; + } else { + cache[key] = true; + } + } + } + + if (isLarge) { + while (++index < length) { + cachePush(array[index]); + } + if (bailout) { + isLarge = caches = objCache = null; + } + } + return isLarge + ? { 'contains': cacheContains, 'push': cachePush } + : { 'contains': basicContains, 'push': basicPush }; + } + /** * Creates compiled iteration functions. * @@ -909,6 +934,17 @@ }; } + /** + * Used by `escape` to convert characters to HTML entities. + * + * @private + * @param {String} match The matched character to escape. + * @returns {String} Returns the escaped character. + */ + function escapeHtmlChar(match) { + return htmlEscapes[match]; + } + /** * Used by `template` to escape characters for inclusion in compiled * string literals. @@ -921,17 +957,6 @@ return '\\' + stringEscapes[match]; } - /** - * Used by `escape` to convert characters to HTML entities. - * - * @private - * @param {String} match The matched character to escape. - * @returns {String} Returns the escaped character. - */ - function escapeHtmlChar(match) { - return htmlEscapes[match]; - } - /** * Checks if `value` is a DOM node in IE < 9. * @@ -967,6 +992,29 @@ // no operation performed } + /** + * Creates a function that juggles arguments, allowing argument overloading + * for `_.flatten` and `_.uniq`, before passing them to the given `func`. + * + * @private + * @param {Function} func The function to wrap. + * @returns {Function} Returns the new function. + */ + function overloadWrapper(func) { + return function(array, flag, callback, thisArg) { + // juggle arguments + if (typeof flag != 'boolean' && flag != null) { + thisArg = callback; + callback = !(thisArg && thisArg[flag] === array) ? flag : undefined; + flag = false; + } + if (callback != null) { + callback = lodash.createCallback(callback, thisArg); + } + return func(array, flag, callback, thisArg); + }; + } + /** * A fallback implementation of `isPlainObject` which checks if a given `value` * is an object created by the `Object` constructor, assuming objects created @@ -1149,7 +1197,7 @@ * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array|Object|String} Returns `collection`. */ - var each = createIterator(eachIteratorOptions); + var basicEach = createIterator(eachIteratorOptions); /** * Used to convert characters to HTML entities: @@ -1334,7 +1382,7 @@ stackB.push(result); // recursively populate clone (susceptible to call stack limits) - (isArr ? each : forOwn)(value, function(objValue, key) { + (isArr ? basicEach : forOwn)(value, function(objValue, key) { result[key] = clone(objValue, deep, callback, undefined, stackA, stackB); }); @@ -2264,7 +2312,7 @@ forIn(object, function(value, key, object) { if (isFunc ? !callback(value, key, object) - : indexOf(props, key) < 0 + : basicIndexOf(props, key) < 0 ) { result[key] = value; } @@ -2392,7 +2440,7 @@ accumulator = createObject(proto); } } - (isArr ? each : forOwn)(object, function(value, index, object) { + (isArr ? basicEach : forOwn)(object, function(value, index, object) { return callback(accumulator, value, index, object); }); return accumulator; @@ -2494,13 +2542,13 @@ result = false; fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0; - if (typeof length == 'number') { + if (length && typeof length == 'number') { result = (isString(collection) ? collection.indexOf(target, fromIndex) - : indexOf(collection, target, fromIndex) + : basicIndexOf(collection, target, fromIndex) ) > -1; } else { - each(collection, function(value) { + basicEach(collection, function(value) { if (++index >= fromIndex) { return !(result = value === target); } @@ -2608,7 +2656,7 @@ } } } else { - each(collection, function(value, index, collection) { + basicEach(collection, function(value, index, collection) { return (result = !!callback(value, index, collection)); }); } @@ -2670,7 +2718,7 @@ } } } else { - each(collection, function(value, index, collection) { + basicEach(collection, function(value, index, collection) { if (callback(value, index, collection)) { result.push(value); } @@ -2737,7 +2785,7 @@ } } else { var result; - each(collection, function(value, index, collection) { + basicEach(collection, function(value, index, collection) { if (callback(value, index, collection)) { result = value; return false; @@ -2780,7 +2828,7 @@ } } } else { - each(collection, callback, thisArg); + basicEach(collection, callback, thisArg); } return collection; } @@ -2915,7 +2963,7 @@ result[index] = callback(collection[index], index, collection); } } else { - each(collection, function(value, key, collection) { + basicEach(collection, function(value, key, collection) { result[++index] = callback(value, key, collection); }); } @@ -2980,7 +3028,7 @@ ? charAtCallback : lodash.createCallback(callback, thisArg); - each(collection, function(value, index, collection) { + basicEach(collection, function(value, index, collection) { var current = callback(value, index, collection); if (current > computed) { computed = current; @@ -3049,7 +3097,7 @@ ? charAtCallback : lodash.createCallback(callback, thisArg); - each(collection, function(value, index, collection) { + basicEach(collection, function(value, index, collection) { var current = callback(value, index, collection); if (current < computed) { computed = current; @@ -3127,7 +3175,7 @@ accumulator = callback(accumulator, collection[index], index, collection); } } else { - each(collection, function(value, index, collection) { + basicEach(collection, function(value, index, collection) { accumulator = noaccum ? (noaccum = false, value) : callback(accumulator, value, index, collection) @@ -3330,7 +3378,7 @@ } } } else { - each(collection, function(value, index, collection) { + basicEach(collection, function(value, index, collection) { return !(result = callback(value, index, collection)); }); } @@ -3655,20 +3703,11 @@ * _.flatten(stooges, 'quotes'); * // => ['Oh, a wise guy, eh?', 'Poifect!', 'Spread out!', 'You knucklehead!'] */ - function flatten(array, isShallow, callback, thisArg) { + var flatten = overloadWrapper(function flatten(array, isShallow, callback) { var index = -1, length = array ? array.length : 0, result = []; - // juggle arguments - if (typeof isShallow != 'boolean' && isShallow != null) { - thisArg = callback; - callback = !(thisArg && thisArg[isShallow] === array) ? isShallow : undefined; - isShallow = false; - } - if (callback != null) { - callback = lodash.createCallback(callback, thisArg); - } while (++index < length) { var value = array[index]; if (callback) { @@ -3682,7 +3721,7 @@ } } return result; - } + }); /** * Gets the index at which the first occurrence of `value` is found using @@ -3709,21 +3748,14 @@ * // => 2 */ function indexOf(array, value, fromIndex) { - var index = -1, - length = array ? array.length : 0; - if (typeof fromIndex == 'number') { - index = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0) - 1; + var length = array ? array.length : 0; + fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0); } else if (fromIndex) { - index = sortedIndex(array, value); + var index = sortedIndex(array, value); return array[index] === value ? index : -1; } - while (++index < length) { - if (array[index] === value) { - return index; - } - } - return -1; + return array ? basicIndexOf(array, value, fromIndex) : -1; } /** @@ -3819,7 +3851,7 @@ function intersection(array) { var args = arguments, argsLength = args.length, - cache = createCache([]), + cache = createCache(), caches = {}, index = -1, length = array ? array.length : 0, @@ -4207,34 +4239,20 @@ * _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); * // => [{ 'x': 1 }, { 'x': 2 }] */ - function uniq(array, isSorted, callback, thisArg) { + var uniq = overloadWrapper(function(array, isSorted, callback) { var index = -1, length = array ? array.length : 0, + isLarge = !isSorted && length >= largeArraySize, result = [], - seen = result; + seen = isLarge ? createCache() : (callback ? [] : result); - // juggle arguments - if (typeof isSorted != 'boolean' && isSorted != null) { - thisArg = callback; - callback = !(thisArg && thisArg[isSorted] === array) ? isSorted : undefined; - isSorted = false; - } - // init value cache for large arrays - var isLarge = !isSorted && length >= largeArraySize; - if (callback != null) { - seen = []; - callback = lodash.createCallback(callback, thisArg); - } - if (isLarge) { - seen = createCache([]); - } while (++index < length) { var value = array[index], computed = callback ? callback(value, index, array) : value; if (isSorted ? !index || seen[seen.length - 1] !== computed - : (isLarge ? !seen.contains(computed) : indexOf(seen, computed) < 0) + : (isLarge ? !seen.contains(computed) : basicIndexOf(seen, computed) < 0) ) { if (callback || isLarge) { seen.push(computed); @@ -4243,7 +4261,7 @@ } } return result; - } + }); /** * The inverse of `_.zip`, this method splits groups of elements into arrays @@ -5626,7 +5644,7 @@ lodash.prototype.valueOf = wrapperValueOf; // add `Array` functions that return unwrapped values - each(['join', 'pop', 'shift'], function(methodName) { + basicEach(['join', 'pop', 'shift'], function(methodName) { var func = arrayProto[methodName]; lodash.prototype[methodName] = function() { return func.apply(this.__wrapped__, arguments); @@ -5634,7 +5652,7 @@ }); // add `Array` functions that return the wrapped value - each(['push', 'reverse', 'sort', 'unshift'], function(methodName) { + basicEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) { var func = arrayProto[methodName]; lodash.prototype[methodName] = function() { func.apply(this.__wrapped__, arguments); @@ -5643,7 +5661,7 @@ }); // add `Array` functions that return new wrapped values - each(['concat', 'slice', 'splice'], function(methodName) { + basicEach(['concat', 'slice', 'splice'], function(methodName) { var func = arrayProto[methodName]; lodash.prototype[methodName] = function() { return new lodashWrapper(func.apply(this.__wrapped__, arguments)); @@ -5653,7 +5671,7 @@ // avoid array-like object bugs with `Array#shift` and `Array#splice` // in Firefox < 10 and IE < 9 if (!support.spliceObjects) { - each(['pop', 'shift', 'splice'], function(methodName) { + basicEach(['pop', 'shift', 'splice'], function(methodName) { var func = arrayProto[methodName], isSplice = methodName == 'splice'; @@ -5670,7 +5688,7 @@ } // add pseudo private property to be used and removed during the build process - lodash._each = each; + lodash._basicEach = basicEach; lodash._iteratorTemplate = iteratorTemplate; lodash._shimKeys = shimKeys;