Change setCallbackData to isBindable and use bindCallback more.

This commit is contained in:
John-David Dalton
2014-12-26 20:56:16 -06:00
parent 8922372f4b
commit 5ea04a388d

131
lodash.js
View File

@@ -1797,20 +1797,15 @@
* @param {*} [func=_.identity] The value to convert to a callback. * @param {*} [func=_.identity] The value to convert to a callback.
* @param {*} [thisArg] The `this` binding of `func`. * @param {*} [thisArg] The `this` binding of `func`.
* @param {number} [argCount] The number of arguments to provide to `func`. * @param {number} [argCount] The number of arguments to provide to `func`.
* @returns {Function} Returns the new function. * @returns {Function} Returns the callback.
*/ */
function baseCallback(func, thisArg, argCount) { function baseCallback(func, thisArg, argCount) {
var type = typeof func; var type = typeof func;
if (type == 'function') { if (type == 'function') {
var data = typeof thisArg != 'undefined' && getData(func); return (typeof thisArg != 'undefined' && isBindable(func))
if (typeof data == 'undefined') { ? bindCallback(func, thisArg, argCount)
setCallbackData(func); : func;
}
// Avoid binding if there are no `this` references or `func` is already bound.
return (data === false || (data !== true && data[1] & BIND_FLAG))
? func
: bindCallback(func, thisArg, argCount);
} }
if (func == null) { if (func == null) {
return identity; return identity;
@@ -2286,9 +2281,9 @@
} }
/** /**
* A specialized version of `baseIsEqual`, for arrays and objects only, which * A specialized version of `baseIsEqual` for arrays and objects which performs
* performs a deep comparison between objects and tracks traversed objects * a deep comparison between objects and tracks traversed objects enabling
* enabling objects with circular references to be compared. * objects with circular references to be compared.
* *
* @private * @private
* @param {Array} object The object to compare to `other`. * @param {Array} object The object to compare to `other`.
@@ -2374,15 +2369,15 @@
* @returns {boolean} Returns `true` if `object` is a match, else `false`. * @returns {boolean} Returns `true` if `object` is a match, else `false`.
*/ */
function baseIsMatch(object, props, values, strictCompareFlags, customizer) { function baseIsMatch(object, props, values, strictCompareFlags, customizer) {
var index = -1, var length = props.length;
length = props.length;
if (object == null) { if (object == null) {
return !length; return !length;
} }
strictCompareFlags || (strictCompareFlags = []); var index = -1,
noCustomizer = !customizer;
while (++index < length) { while (++index < length) {
if (strictCompareFlags[index] if ((noCustomizer && strictCompareFlags[index])
? values[index] !== object[props[index]] ? values[index] !== object[props[index]]
: !hasOwnProperty.call(object, props[index]) : !hasOwnProperty.call(object, props[index])
) { ) {
@@ -2392,7 +2387,7 @@
index = -1; index = -1;
while (++index < length) { while (++index < length) {
var key = props[index]; var key = props[index];
if (strictCompareFlags[index]) { if (noCustomizer && strictCompareFlags[index]) {
var result = hasOwnProperty.call(object, key); var result = hasOwnProperty.call(object, key);
} else { } else {
var objValue = object[key], var objValue = object[key],
@@ -2775,16 +2770,22 @@
} }
/** /**
* A specialized version of `_.bind` for callbacks with support for specifying * A specialized version of `baseCallback` which only supports `this` binding
* the number of arguments to provide to `func`. * and specifying the number of arguments to provide to `func`.
* *
* @private * @private
* @param {Function} func The function to bind. * @param {Function} func The function to bind.
* @param {*} thisArg The `this` binding of `func`. * @param {*} thisArg The `this` binding of `func`.
* @param {number} [argCount] The number of arguments to provide to `func`. * @param {number} [argCount] The number of arguments to provide to `func`.
* @returns {Function} Returns the new function. * @returns {Function} Returns the callback.
*/ */
function bindCallback(func, thisArg, argCount) { function bindCallback(func, thisArg, argCount) {
if (typeof func != 'function') {
return identity;
}
if (typeof thisArg == 'undefined') {
return func;
}
switch (argCount) { switch (argCount) {
case 1: return function(value) { case 1: return function(value) {
return func.call(thisArg, value); return func.call(thisArg, value);
@@ -2963,7 +2964,7 @@
} }
// Juggle arguments. // Juggle arguments.
if (length > 3 && typeof arguments[length - 2] == 'function') { if (length > 3 && typeof arguments[length - 2] == 'function') {
var customizer = baseCallback(arguments[--length - 1], arguments[length--], 5); var customizer = bindCallback(arguments[--length - 1], arguments[length--], 5);
} else if (length > 2 && typeof arguments[length - 1] == 'function') { } else if (length > 2 && typeof arguments[length - 1] == 'function') {
customizer = arguments[--length]; customizer = arguments[--length];
} }
@@ -3571,6 +3572,33 @@
(arrayLikeClasses[toString.call(value)] || (!lodash.support.argsClass && isArguments(value)))) || false; (arrayLikeClasses[toString.call(value)] || (!lodash.support.argsClass && isArguments(value)))) || false;
} }
/**
* Checks if `func` is eligible for `this` binding.
*
* @private
* @param {Function} func The function to check.
* @returns {boolean} Returns `true` if `func` is eligible, else `false`.
*/
function isBindable(func) {
var support = lodash.support;
if (support.funcNames) {
var result = !func.name;
}
result = result || !support.funcDecomp;
if (!result) {
var source = fnToString.call(func);
if (!support.funcNames) {
result = !reFuncName.test(source);
}
if (!result) {
// Check if `func` references the `this` keyword and store the result.
result = reThis.test(source) || isNative(func);
baseSetData(func, result);
}
}
return result;
}
/** /**
* Checks if `value` is cloneable. * Checks if `value` is cloneable.
* *
@@ -3806,34 +3834,6 @@
}; };
}()); }());
/**
* A specialized version of `setData` for callbacks which sets metadata to
* indicate whether `func` is eligible for `this` binding.
*
* @private
* @param {Function} func The function to associate metadata with.
* @returns {Function} Returns `func`.
*/
function setCallbackData(func) {
var support = lodash.support;
if (support.funcNames) {
var data = !func.name;
}
data = data || !support.funcDecomp;
if (!data) {
var source = fnToString.call(func);
if (!support.funcNames) {
data = !reFuncName.test(source);
}
if (!data) {
// Check if `func` references the `this` keyword and store the result.
data = reThis.test(source) || isNative(func);
baseSetData(func, data);
}
}
return func;
}
/** /**
* A fallback implementation of `_.isPlainObject` which checks if `value` * A fallback implementation of `_.isPlainObject` which checks if `value`
* is an object created by the `Object` constructor or has a `[[Prototype]]` * is an object created by the `Object` constructor or has a `[[Prototype]]`
@@ -5748,7 +5748,7 @@
function forEach(collection, iteratee, thisArg) { function forEach(collection, iteratee, thisArg) {
return (typeof iteratee == 'function' && typeof thisArg == 'undefined' && isArray(collection)) return (typeof iteratee == 'function' && typeof thisArg == 'undefined' && isArray(collection))
? arrayEach(collection, iteratee) ? arrayEach(collection, iteratee)
: baseEach(collection, baseCallback(iteratee, thisArg, 3)); : baseEach(collection, bindCallback(iteratee, thisArg, 3));
} }
/** /**
@@ -5771,7 +5771,7 @@
function forEachRight(collection, iteratee, thisArg) { function forEachRight(collection, iteratee, thisArg) {
return (typeof iteratee == 'function' && typeof thisArg == 'undefined' && isArray(collection)) return (typeof iteratee == 'function' && typeof thisArg == 'undefined' && isArray(collection))
? arrayEachRight(collection, iteratee) ? arrayEachRight(collection, iteratee)
: baseEachRight(collection, baseCallback(iteratee, thisArg, 3)); : baseEachRight(collection, bindCallback(iteratee, thisArg, 3));
} }
/** /**
@@ -7563,7 +7563,7 @@
customizer = isIterateeCall(value, isDeep, thisArg) ? null : isDeep; customizer = isIterateeCall(value, isDeep, thisArg) ? null : isDeep;
isDeep = false; isDeep = false;
} }
customizer = typeof customizer == 'function' && baseCallback(customizer, thisArg, 1); customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1);
return baseClone(value, isDeep, customizer); return baseClone(value, isDeep, customizer);
} }
@@ -7611,7 +7611,7 @@
* // => false * // => false
*/ */
function cloneDeep(value, customizer, thisArg) { function cloneDeep(value, customizer, thisArg) {
customizer = typeof customizer == 'function' && baseCallback(customizer, thisArg, 1); customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 1);
return baseClone(value, true, customizer); return baseClone(value, true, customizer);
} }
@@ -7810,7 +7810,7 @@
* // => true * // => true
*/ */
function isEqual(value, other, customizer, thisArg) { function isEqual(value, other, customizer, thisArg) {
customizer = typeof customizer == 'function' && baseCallback(customizer, thisArg, 3); customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 3);
if (!customizer && isStrictComparable(value) && isStrictComparable(other)) { if (!customizer && isStrictComparable(value) && isStrictComparable(other)) {
return value === other; return value === other;
} }
@@ -7975,10 +7975,8 @@
var props = keys(source), var props = keys(source),
length = props.length; length = props.length;
if (typeof customizer == 'function') { customizer = typeof customizer == 'function' && bindCallback(customizer, thisArg, 3);
customizer = baseCallback(customizer, thisArg, 3); if (!customizer && length == 1) {
}
else if (length == 1) {
var key = props[0], var key = props[0],
value = source[key]; value = source[key];
@@ -8418,7 +8416,7 @@
*/ */
function forIn(object, iteratee, thisArg) { function forIn(object, iteratee, thisArg) {
if (typeof iteratee != 'function' || typeof thisArg != 'undefined') { if (typeof iteratee != 'function' || typeof thisArg != 'undefined') {
iteratee = baseCallback(iteratee, thisArg, 3); iteratee = bindCallback(iteratee, thisArg, 3);
} }
return baseFor(object, iteratee, keysIn); return baseFor(object, iteratee, keysIn);
} }
@@ -8449,7 +8447,7 @@
* // => logs 'z', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 'z' * // => logs 'z', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 'z'
*/ */
function forInRight(object, iteratee, thisArg) { function forInRight(object, iteratee, thisArg) {
iteratee = baseCallback(iteratee, thisArg, 3); iteratee = bindCallback(iteratee, thisArg, 3);
return baseForRight(object, iteratee, keysIn); return baseForRight(object, iteratee, keysIn);
} }
@@ -8475,7 +8473,7 @@
*/ */
function forOwn(object, iteratee, thisArg) { function forOwn(object, iteratee, thisArg) {
if (typeof iteratee != 'function' || typeof thisArg != 'undefined') { if (typeof iteratee != 'function' || typeof thisArg != 'undefined') {
iteratee = baseCallback(iteratee, thisArg, 3); iteratee = bindCallback(iteratee, thisArg, 3);
} }
return baseForOwn(object, iteratee); return baseForOwn(object, iteratee);
} }
@@ -8499,7 +8497,7 @@
* // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length' * // => logs 'length', '1', and '0' assuming `_.forOwn` logs '0', '1', and 'length'
*/ */
function forOwnRight(object, iteratee, thisArg) { function forOwnRight(object, iteratee, thisArg) {
iteratee = baseCallback(iteratee, thisArg, 3); iteratee = bindCallback(iteratee, thisArg, 3);
return baseForRight(object, iteratee, keys); return baseForRight(object, iteratee, keys);
} }
@@ -8742,7 +8740,7 @@
function mapValues(object, iteratee, thisArg) { function mapValues(object, iteratee, thisArg) {
iteratee = getCallback(iteratee, thisArg, 3); iteratee = getCallback(iteratee, thisArg, 3);
var result = {} var result = {};
baseForOwn(object, function(value, key, object) { baseForOwn(object, function(value, key, object) {
result[key] = iteratee(value, key, object); result[key] = iteratee(value, key, object);
}); });
@@ -9984,7 +9982,7 @@
* @param {*} [func=_.identity] The value to convert to a callback. * @param {*} [func=_.identity] The value to convert to a callback.
* @param {*} [thisArg] The `this` binding of `func`. * @param {*} [thisArg] The `this` binding of `func`.
* @param- {Object} [guard] Enables use as a callback for functions like `_.map`. * @param- {Object} [guard] Enables use as a callback for functions like `_.map`.
* @returns {Function} Returns the new function. * @returns {Function} Returns the callback.
* @example * @example
* *
* var users = [ * var users = [
@@ -10337,11 +10335,10 @@
if (n < 1 || !nativeIsFinite(n)) { if (n < 1 || !nativeIsFinite(n)) {
return []; return [];
} }
iteratee = baseCallback(iteratee, thisArg, 1);
var index = -1, var index = -1,
result = Array(nativeMin(n, MAX_ARRAY_LENGTH)); result = Array(nativeMin(n, MAX_ARRAY_LENGTH));
iteratee = bindCallback(iteratee, thisArg, 1);
while (++index < n) { while (++index < n) {
if (index < MAX_ARRAY_LENGTH) { if (index < MAX_ARRAY_LENGTH) {
result[index] = iteratee(index); result[index] = iteratee(index);