Add baseCreateCallback to avoid circular deps add more varDeps to fix large array caching.

Former-commit-id: f8164bbff59a3ad294c5670693942dc56a1c88a5
This commit is contained in:
John-David Dalton
2013-08-01 00:12:53 -07:00
parent 9a935ba90c
commit c97e653ba1
3 changed files with 159 additions and 134 deletions

View File

@@ -110,13 +110,13 @@
'bind': ['createBound'],
'bindAll': ['baseFlatten', 'bind', 'functions'],
'bindKey': ['createBound'],
'clone': ['baseClone', 'createCallback'],
'cloneDeep': ['baseClone', 'createCallback'],
'clone': ['baseClone', 'baseCreateCallback'],
'cloneDeep': ['baseClone', 'baseCreateCallback'],
'compact': [],
'compose': [],
'contains': ['baseEach', 'getIndexOf', 'isString'],
'countBy': ['createAggregator'],
'createCallback': ['baseIsEqual', 'bind', 'identity', 'isObject', 'keys', 'setBindData'],
'createCallback': ['baseCreateCallback', 'baseIsEqual', 'isObject', 'keys'],
'debounce': ['isObject'],
'defaults': ['createIterator'],
'defer': ['bind'],
@@ -133,12 +133,12 @@
'findLastKey': ['createCallback', 'forOwnRight'],
'first': ['createCallback', 'slice'],
'flatten': ['baseFlatten', 'map'],
'forEach': ['baseEach', 'createCallback', 'isArray'],
'forEachRight': ['createCallback', 'forEach', 'isString', 'keys'],
'forEach': ['baseCreateCallback', 'baseEach', 'isArray'],
'forEachRight': ['baseCreateCallback', 'forEach', 'isString', 'keys'],
'forIn': ['createIterator'],
'forInRight': ['createCallback', 'forIn'],
'forInRight': ['baseCreateCallback', 'forIn'],
'forOwn': ['createIterator'],
'forOwnRight': ['createCallback', 'keys'],
'forOwnRight': ['baseCreateCallback', 'keys'],
'functions': ['forIn', 'isFunction'],
'groupBy': ['createAggregator'],
'has': [],
@@ -155,7 +155,7 @@
'isDate': [],
'isElement': [],
'isEmpty': ['forOwn', 'isArguments', 'isFunction'],
'isEqual': ['baseIsEqual', 'createCallback'],
'isEqual': ['baseCreateCallback', 'baseIsEqual'],
'isFinite': [],
'isFunction': [],
'isNaN': ['isNumber'],
@@ -172,7 +172,7 @@
'map': ['baseEach', 'createCallback', 'isArray'],
'max': ['baseEach', 'charAtCallback', 'createCallback', 'isArray', 'isString'],
'memoize': [],
'merge': ['baseMerge', 'createCallback', 'getArray', 'isObject', 'releaseArray'],
'merge': ['baseCreateCallback', 'baseMerge', 'getArray', 'isObject', 'releaseArray'],
'min': ['baseEach', 'charAtCallback', 'createCallback', 'isArray', 'isString'],
'mixin': ['forEach', 'functions', 'isFunction'],
'noConflict': [],
@@ -187,8 +187,8 @@
'pull': [],
'random': [],
'range': [],
'reduce': ['baseEach', 'createCallback', 'isArray'],
'reduceRight': ['createCallback', 'forEachRight'],
'reduce': ['baseCreateCallback', 'baseEach', 'isArray'],
'reduceRight': ['baseCreateCallback', 'forEachRight'],
'reject': ['createCallback', 'filter'],
'remove': ['baseEach', 'createCallback', 'isArray'],
'rest': ['createCallback', 'slice'],
@@ -202,9 +202,9 @@
'tap': ['value'],
'template': ['defaults', 'escape', 'escapeStringChar', 'keys', 'values'],
'throttle': ['debounce', 'getObject', 'isObject', 'releaseObject'],
'times': ['createCallback'],
'times': ['baseCreateCallback'],
'toArray': ['isString', 'slice', 'values'],
'transform': ['createCallback', 'createObject', 'forOwn', 'isArray'],
'transform': ['baseCreateCallback', 'createObject', 'forOwn', 'isArray'],
'unescape': ['keys', 'unescapeHtmlChar'],
'union': ['baseFlatten', 'baseUniq'],
'uniq': ['baseUniq', 'createCallback'],
@@ -219,6 +219,7 @@
// private functions
'baseClone': ['assign', 'baseEach', 'forOwn', 'getArray', 'isArray', 'isObject', 'isNode', 'releaseArray', 'slice'],
'baseCreateCallback': ['bind', 'identity', 'setBindData'],
'baseEach': ['createIterator'],
'baseFlatten': ['isArguments', 'isArray'],
'baseIndexOf': [],
@@ -232,7 +233,7 @@
'createAggregator': ['createCallback', 'forEach'],
'createBound': ['createObject', 'isFunction', 'isObject', 'setBindData'],
'createCache': ['cachePush', 'getObject', 'releaseObject'],
'createIterator': ['getObject', 'isArguments', 'isArray', 'isString', 'iteratorTemplate', 'lodash', 'releaseObject'],
'createIterator': ['baseCreateCallback', 'getObject', 'isArguments', 'isArray', 'isString', 'iteratorTemplate', 'releaseObject'],
'createObject': [ 'isObject', 'noop'],
'escapeHtmlChar': [],
'escapeStringChar': [],
@@ -283,24 +284,34 @@
'assign': ['defaultsIteratorOptions'],
'baseEach': ['eachIteratorOptions'],
'baseIsEqual': ['objectTypes'],
'baseUniq': ['largeArraySize'],
'bind': ['reNative'],
'cacheIndexOf': ['keyPrefix'],
'cachePush': ['keyPrefix'],
'createIterator': ['indicatorObject', 'objectTypes'],
'createBound': ['reNative'],
'createObject': ['reNative'],
'defaults': ['defaultsIteratorOptions'],
'defer': ['objectTypes', 'reNative'],
'difference': ['largeArraySize'],
'escape': ['reUnescapedHtml'],
'escapeHtmlChar': ['htmlEscapes'],
'forIn': ['eachIteratorOptions', 'forOwnIteratorOptions'],
'forOwn': ['eachIteratorOptions', 'forOwnIteratorOptions'],
'forOwnIteratorOptions': ['eachIteratorOptions'],
'getArray': ['arrayPool'],
'getObject': ['objectPool'],
'htmlUnescapes': ['htmlEscapes'],
'intersection': ['largeArraySize'],
'isArray': ['reNative'],
'isObject': ['objectTypes'],
'isPlainObject': ['reNative'],
'isRegExp': ['objectTypes'],
'keys': ['reNative'],
'memoize': ['keyPrefix'],
'reEscapedHtml': ['htmlUnescapes'],
'releaseArray': ['arrayPool', 'maxPoolSize'],
'releaseObject': ['maxPoolSize', 'objectPool'],
'reUnescapedHtml': ['htmlEscapes'],
'setBindData': ['reNative'],
'support': ['reNative'],
@@ -566,6 +577,7 @@
/** List of private functions */
var privateFuncs = [
'baseClone',
'baseCreateCallback',
'baseEach',
'baseFlatten',
'baseIndexOf',
@@ -752,10 +764,10 @@
}
/**
* Creates modules for each of the specified `identifiers`.
* Creates modules based on the build state passed.
*
* @private
* @param {Object} state An array identifiers to modularize.
* @param {Object} state The build state object.
*/
function buildModule(state) {
var buildFuncs = state.buildFuncs,
@@ -1614,8 +1626,8 @@
});
// remove `__bindData__` logic and `setBindData` function calls from `_.createCallback`
source = source.replace(matchFunction(source, 'createCallback'), function(match) {
// remove `__bindData__` logic and `setBindData` function calls from `baseCreateCallback`
source = source.replace(matchFunction(source, 'baseCreateCallback'), function(match) {
return match
.replace(/(?:\s*\/\/.*)*\n( *)var bindData *=[\s\S]+?\n\1}/, '')
.replace(/(?:\s*\/\/.*)*\n( *)if *\(bindData[\s\S]+?\n\1}/, '');
@@ -1728,7 +1740,18 @@
source = removeFunction(source, 'getIndexOf');
// replace all `getIndexOf` calls with `baseIndexOf`
source = source.replace(/\bgetIndexOf\(\)/g, 'baseIndexOf');
_.each(['baseUniq', 'contains', 'difference', 'intersection', 'omit'], function(funcName) {
source = source.replace(matchFunction(source, funcName), function(match) {
return match.replace(/\bgetIndexOf\(\)/g, 'baseIndexOf');
});
});
// simplify `isLarge` assignments
_.each(['baseUniq', 'difference'], function(funcName) {
source = source.replace(matchFunction(source, funcName), function(match) {
return match.replace(/\b(largeArraySize).+?baseIndexOf\b/g, '$1');
});
});
return source;
}
@@ -2146,8 +2169,8 @@
return match.replace(/^ *if *\(support\.unindexedChars[^}]+}\n+/m, '');
});
// remove `support.unindexedChars` from `_.reduceRight`
source = source.replace(matchFunction(source, 'reduceRight'), function(match) {
// remove `support.unindexedChars` from `_.forEachRight`
source = source.replace(matchFunction(source, 'forEachRight'), function(match) {
return match.replace(/}\s*else if *\(support\.unindexedChars[^}]+/, '');
});
@@ -2723,7 +2746,7 @@
});
}
if (isLegacy || isMobile || isUnderscore) {
_.each(['createBound', 'createCallback'], function(funcName) {
_.each(['baseCreateCallback', 'createBound'], function(funcName) {
_.pull(funcDepMap[funcName], 'setBindData');
});
}
@@ -2782,19 +2805,12 @@
}
});
_.each(['clone', 'isEqual', 'omit', 'pick'], function(funcName) {
if (funcName == 'isEqual') {
if (isLodash('baseIsEqual') || isLodash('isEqual')) {
return;
}
}
if (funcName == 'clone') {
if (isLodash('baseClone') || isLodash('clone') || isLodash('cloneDeep')) {
return;
}
}
if (!isLodash(funcName)) {
_.pull(funcDepMap[funcName], 'createCallback');
_.each(['isEqual', 'omit', 'pick'], function(funcName) {
if (funcName == 'isEqual'
? (!isLodash('baseIsEqual') && !isLodash('isEqual'))
: !isLodash(funcName)
) {
_.pull(funcDepMap[funcName], 'baseCreateCallback', 'createCallback');
}
});
@@ -2818,8 +2834,8 @@
var deps = _.pull(funcDepMap[funcName], 'createIterator');
_.pull(varDepMap[funcName] || (varDepMap[funcName] = []), 'defaultsIteratorOptions', 'eachIteratorOptions', 'forOwnIteratorOptions').push('objectTypes');
if (funcName != 'shimKeys') {
deps.push('createCallback');
if (funcName != 'defaults' && funcName != 'shimKeys') {
deps.push('baseCreateCallback');
}
if (funcName != 'forIn' && funcName != 'shimKeys') {
deps.push('keys');
@@ -2882,7 +2898,6 @@
}
}
if (isModularize) {
funcDepMap.createIterator.push('createCallback');
_.forOwn(funcDepMap, function(deps, funcName) {
if (_.contains(deps, 'getIndexOf')) {
_.pull(deps, 'getIndexOf').push('baseIndexOf');
@@ -3061,7 +3076,7 @@
' var index = -1,',
' length = collection ? collection.length : 0;',
'',
" callback = callback && typeof thisArg == 'undefined' ? callback : lodash.createCallback(callback, thisArg, 3);",
" callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3);",
" if (typeof length == 'number') {",
' while (++index < length) {',
' if (callback(collection[index], index, collection) === false) {',
@@ -4217,11 +4232,6 @@
return match.replace(/(:\s*)lodash\b/, "$1{ 'escape': escape }");
});
// replace `lodash` with `createCallback` in `createIterator`
source = source.replace(matchFunction(source, 'createIterator'), function(match) {
return match.replace(/\blodash\b/g, 'createCallback');
});
// remove unneeded variable dependencies
_.each(varDependencies, function(varName) {
if (!_.contains(includeVars, varName)) {

View File

@@ -10,6 +10,7 @@
'args',
'argsIndex',
'argsLength',
'baseCreateCallback',
'callback',
'className',
'collection',

194
lodash.js
View File

@@ -143,7 +143,7 @@
/*--------------------------------------------------------------------------*/
/**
* A base implementation of `_.indexOf` without support for binary searches
* The base implementation of `_.indexOf` without support for binary searches
* or `fromIndex` constraints.
*
* @private
@@ -945,7 +945,7 @@
/*--------------------------------------------------------------------------*/
/**
* A base implementation of `_.clone` without argument juggling or support
* The base implementation of `_.clone` without argument juggling or support
* for `thisArg` binding.
*
* @private
@@ -1035,7 +1035,52 @@
}
/**
* A base implementation of `_.flatten` without support for `callback`
* The base implementation of `_.createCallback` without support for creating
* "_.pluck" or "_.where" style callbacks.
*
* @private
* @param {Mixed} [func=identity] The value to convert to a callback.
* @param {Mixed} [thisArg] The `this` binding of the created callback.
* @param {Number} [argCount] The number of arguments the callback accepts.
* @returns {Function} Returns a callback function.
*/
function baseCreateCallback(func, thisArg, argCount) {
if (typeof func != 'function') {
return identity;
}
// exit early if there is no `thisArg`
if (typeof thisArg == 'undefined') {
return func;
}
var bindData = !func.name || func.__bindData__;
if (typeof bindData == 'undefined') {
// checks if `func` references the `this` keyword and stores the result
bindData = !reThis || reThis.test(fnToString.call(func));
setBindData(func, bindData);
}
// exit early if there are no `this` references or `func` is bound
if (bindData !== true && !(bindData && bindData[4])) {
return func;
}
switch (argCount) {
case 1: return function(value) {
return func.call(thisArg, value);
};
case 2: return function(a, b) {
return func.call(thisArg, a, b);
};
case 3: return function(value, index, collection) {
return func.call(thisArg, value, index, collection);
};
case 4: return function(accumulator, value, index, collection) {
return func.call(thisArg, accumulator, value, index, collection);
};
}
return bind(func, thisArg);
}
/**
* The base implementation of `_.flatten` without support for `callback`
* shorthands or `thisArg` binding.
*
* @private
@@ -1063,7 +1108,7 @@
}
/**
* A base implementation of `_.isEqual`, without support for `thisArg` binding,
* The base implementation of `_.isEqual`, without support for `thisArg` binding,
* that allows partial "_.where" style comparisons.
*
* @private
@@ -1232,7 +1277,7 @@
}
/**
* A base implementation of `_.merge` without argument juggling or support
* The base implementation of `_.merge` without argument juggling or support
* for `thisArg` binding.
*
* @private
@@ -1297,7 +1342,7 @@
}
/**
* A base implementation of `_.uniq` without support for `callback` shorthands
* The base implementation of `_.uniq` without support for `callback` shorthands
* or `thisArg` binding.
*
* @private
@@ -1485,9 +1530,9 @@
// create the function factory
var factory = Function(
'errorClass, errorProto, hasOwnProperty, indicatorObject, isArguments, ' +
'isArray, isString, keys, lodash, objectProto, objectTypes, nonEnumProps, ' +
'stringClass, stringProto, toString',
'baseCreateCallback, errorClass, errorProto, hasOwnProperty, ' +
'indicatorObject, isArguments, isArray, isString, keys, objectProto, ' +
'objectTypes, nonEnumProps, stringClass, stringProto, toString',
'return function(' + args + ') {\n' + iteratorTemplate(data) + '\n}'
);
@@ -1495,9 +1540,9 @@
// return the compiled function
return factory(
errorClass, errorProto, hasOwnProperty, indicatorObject, isArguments,
isArray, isString, data.keys, lodash, objectProto, objectTypes, nonEnumProps,
stringClass, stringProto, toString
baseCreateCallback, errorClass, errorProto, hasOwnProperty,
indicatorObject, isArguments, isArray, isString, data.keys, objectProto,
objectTypes, nonEnumProps, stringClass, stringProto, toString
);
}
@@ -1704,7 +1749,7 @@
/** Reusable iterator options shared by `each`, `forIn`, and `forOwn` */
var eachIteratorOptions = {
'args': 'collection, callback, thisArg',
'top': "callback = callback && typeof thisArg == 'undefined' ? callback : lodash.createCallback(callback, thisArg, 3)",
'top': "callback = callback && typeof thisArg == 'undefined' ? callback : baseCreateCallback(callback, thisArg, 3)",
'array': "typeof length == 'number'",
'keys': keys,
'loop': 'if (callback(iterable[index], index, collection) === false) return result'
@@ -1807,7 +1852,7 @@
defaultsIteratorOptions.top.replace(';',
';\n' +
"if (argsLength > 3 && typeof args[argsLength - 2] == 'function') {\n" +
' var callback = lodash.createCallback(args[--argsLength - 1], args[argsLength--], 2);\n' +
' var callback = baseCreateCallback(args[--argsLength - 1], args[argsLength--], 2);\n' +
"} else if (argsLength > 2 && typeof args[argsLength - 1] == 'function') {\n" +
' callback = args[--argsLength];\n' +
'}'
@@ -1863,7 +1908,7 @@
callback = deep;
deep = false;
}
return baseClone(value, deep, typeof callback == 'function' && lodash.createCallback(callback, thisArg, 1));
return baseClone(value, deep, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
}
/**
@@ -1908,7 +1953,7 @@
* // => false
*/
function cloneDeep(value, callback, thisArg) {
return baseClone(value, true, typeof callback == 'function' && lodash.createCallback(callback, thisArg, 1));
return baseClone(value, true, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1));
}
/**
@@ -2065,7 +2110,7 @@
});
var length = pairs.length;
callback = lodash.createCallback(callback, thisArg, 3);
callback = baseCreateCallback(callback, thisArg, 3);
while (++index < length) {
if (callback(pairs[index], pairs[++index], object) === false) {
break;
@@ -2119,7 +2164,7 @@
var props = keys(object),
length = props.length;
callback = lodash.createCallback(callback, thisArg, 3);
callback = baseCreateCallback(callback, thisArg, 3);
while (length--) {
var key = props[length];
if (callback(object[key], key, object) === false) {
@@ -2329,7 +2374,7 @@
* // => true
*/
function isEqual(a, b, callback, thisArg) {
return baseIsEqual(a, b, typeof callback == 'function' && lodash.createCallback(callback, thisArg, 2));
return baseIsEqual(a, b, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 2));
}
/**
@@ -2636,7 +2681,7 @@
length = args.length;
}
if (length > 3 && typeof args[length - 2] == 'function') {
var callback = lodash.createCallback(args[--length - 1], args[length--], 2);
var callback = baseCreateCallback(args[--length - 1], args[length--], 2);
} else if (length > 2 && typeof args[length - 1] == 'function') {
callback = args[--length];
}
@@ -2810,7 +2855,7 @@
*/
function transform(object, callback, accumulator, thisArg) {
var isArr = isArray(object);
callback = lodash.createCallback(callback, thisArg, 4);
callback = baseCreateCallback(callback, thisArg, 4);
if (accumulator == null) {
if (isArr) {
@@ -3269,7 +3314,7 @@
} else if (support.unindexedChars && isString(collection)) {
iterable = collection.split('');
}
callback = lodash.createCallback(callback, thisArg, 3);
callback = baseCreateCallback(callback, thisArg, 3);
forEach(collection, function(value, index, collection) {
index = props ? props[--length] : --length;
callback(iterable[index], index, collection);
@@ -3643,7 +3688,7 @@
*/
function reduce(collection, callback, accumulator, thisArg) {
var noaccum = arguments.length < 3;
callback = lodash.createCallback(callback, thisArg, 4);
callback = baseCreateCallback(callback, thisArg, 4);
if (isArray(collection)) {
var index = -1,
@@ -3686,7 +3731,7 @@
*/
function reduceRight(collection, callback, accumulator, thisArg) {
var noaccum = arguments.length < 3;
callback = lodash.createCallback(callback, thisArg, 4);
callback = baseCreateCallback(callback, thisArg, 4);
forEachRight(collection, function(value, index, collection) {
accumulator = noaccum
? (noaccum = false, value)
@@ -3785,7 +3830,8 @@
var value = collection[index];
if (callback(value, index, collection)) {
result.push(value);
splice.call(collection, index, 1);
splice.call(collection, index--, 1);
length--;
}
}
} else {
@@ -4602,7 +4648,8 @@
value = args[argsIndex];
while (++index < length) {
if (array[index] === value) {
splice.call(array, index, 1);
splice.call(array, index--, 1);
length--;
}
}
}
@@ -5131,8 +5178,6 @@
* If `func` is an object, the created callback will return `true` for elements
* that contain the equivalent object properties, otherwise it will return `false`.
*
* Note: All Lo-Dash methods, that accept a `callback` argument, use `_.createCallback`.
*
* @static
* @memberOf _
* @category Functions
@@ -5172,71 +5217,40 @@
* // => { 'moe': { 'name': 'moe', 'age': 40 }, 'larry': { 'name': 'larry', 'age': 50 } }
*/
function createCallback(func, thisArg, argCount) {
if (func == null) {
return identity;
}
var type = typeof func;
if (type != 'function') {
// handle "_.pluck" style callback shorthands
if (type != 'object') {
return function(object) {
return object[func];
};
}
var props = keys(func),
key = props[0],
a = func[key];
// handle "_.where" style callback shorthands
if (props.length == 1 && a === a && !isObject(a)) {
// fast path the common case of passing an object with a single
// property containing a primitive value
return function(object) {
var b = object[key];
return a === b && (a !== 0 || (1 / a == 1 / b));
};
}
if (func == null || type == 'function') {
return baseCreateCallback(func, thisArg, argCount);
}
// handle "_.pluck" style callback shorthands
if (type != 'object') {
return function(object) {
var length = props.length,
result = false;
return object[func];
};
}
var props = keys(func),
key = props[0],
a = func[key];
while (length--) {
if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) {
break;
}
// handle "_.where" style callback shorthands
if (props.length == 1 && a === a && !isObject(a)) {
// fast path the common case of passing an object with a single
// property containing a primitive value
return function(object) {
var b = object[key];
return a === b && (a !== 0 || (1 / a == 1 / b));
};
}
return function(object) {
var length = props.length,
result = false;
while (length--) {
if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) {
break;
}
return result;
};
}
// exit early if there is no `thisArg`
if (typeof thisArg == 'undefined') {
return func;
}
var bindData = !func.name || func.__bindData__;
if (typeof bindData == 'undefined') {
// checks if `func` references the `this` keyword and stores the result
bindData = !reThis || reThis.test(fnToString.call(func));
setBindData(func, bindData);
}
// exit early if there are no `this` references or `func` is bound
if (bindData !== true && !(bindData && bindData[4])) {
return func;
}
switch (argCount) {
case 1: return function(value) {
return func.call(thisArg, value);
};
case 2: return function(a, b) {
return func.call(thisArg, a, b);
};
case 3: return function(value, index, collection) {
return func.call(thisArg, value, index, collection);
};
case 4: return function(accumulator, value, index, collection) {
return func.call(thisArg, accumulator, value, index, collection);
};
}
return bind(func, thisArg);
}
return result;
};
}
/**
@@ -6013,7 +6027,7 @@
var index = -1,
result = Array(n);
callback = lodash.createCallback(callback, thisArg, 1);
callback = baseCreateCallback(callback, thisArg, 1);
while (++index < n) {
result[index] = callback(index);
}