Fix placeholder support without metadata.

This commit is contained in:
John-David Dalton
2014-07-24 21:29:22 -07:00
parent 3004c58798
commit e402347d73
2 changed files with 57 additions and 79 deletions

100
lodash.js
View File

@@ -39,6 +39,9 @@
*/ */
var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1; var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1;
/** Used as the internal argument placeholder */
var PLACEHOLDER = '__lodash_placeholder__';
/** Used to generate unique IDs */ /** Used to generate unique IDs */
var idCounter = 0; var idCounter = 0;
@@ -1068,26 +1071,6 @@
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/**
* Appends placeholder indexes to `array` adding `offset` to each appended index.
*
* @private
* @param {Array} array The array of placeholder indexes to append to.
* @param {Array} indexes The array of placeholder indexes to append.
* @param {number} offset The placeholder offset.
* @returns {Array} Returns `array`.
*/
function appendHolders(array, indexes, offset) {
var length = array.length,
index = indexes.length;
array.length += index;
while (index--) {
array[length + index] = indexes[index] + offset;
}
return array;
}
/** /**
* A specialized version of `_.forEach` for arrays without support for * A specialized version of `_.forEach` for arrays without support for
* callback shorthands or `this` binding. * callback shorthands or `this` binding.
@@ -1599,7 +1582,7 @@
} }
if (isCurry || isCurryRight) { if (isCurry || isCurryRight) {
var placeholder = wrapper.placeholder, var placeholder = wrapper.placeholder,
newPartialHolders = getHolders(args, placeholder); newPartialHolders = replaceHolders(args, placeholder);
length -= newPartialHolders.length; length -= newPartialHolders.length;
@@ -2831,29 +2814,21 @@
} }
// append partial left arguments // append partial left arguments
if (isPartial) { if (isPartial) {
var partialHolders = data[5], var funcPartialArgs = funcData[4];
funcPartialArgs = funcData[4];
if (funcPartialArgs) { if (funcPartialArgs) {
appendHolders(funcData[5], partialHolders, funcPartialArgs.length); funcPartialArgs = composeArgs(funcPartialArgs, funcData[5], partialArgs);
push.apply(funcPartialArgs, partialArgs);
} else {
funcData[4] = partialArgs;
funcData[5] = partialHolders;
} }
funcData[4] = funcPartialArgs || partialArgs;
funcData[5] = funcPartialArgs ? replaceHolders(funcPartialArgs, PLACEHOLDER) : data[5];
} }
// prepend partial right arguments // prepend partial right arguments
if (isPartialRight) { if (isPartialRight) {
var partialRightHolders = data[7], var funcPartialRightArgs = funcData[6];
funcPartialRightArgs = funcData[6];
if (funcPartialRightArgs) { if (funcPartialRightArgs) {
appendHolders(funcData[7], partialRightHolders, funcPartialRightArgs.length); funcPartialRightArgs = composeArgsRight(funcPartialRightArgs, funcData[7], partialRightArgs);
unshift.apply(funcPartialRightArgs, partialRightArgs);
} else {
funcData[6] = partialRightArgs;
funcData[7] = partialRightHolders;
} }
funcData[6] = funcPartialRightArgs || partialRightArgs;
funcData[7] = funcPartialRightArgs ? replaceHolders(funcPartialRightArgs, PLACEHOLDER) : data[7];
} }
// merge flags // merge flags
funcData[1] |= bitmask; funcData[1] |= bitmask;
@@ -2881,26 +2856,6 @@
return arguments.length ? result(func, thisArg, argCount) : result; return arguments.length ? result(func, thisArg, argCount) : result;
} }
/**
* Finds the indexes of all placeholder elements in `array`.
*
* @private
* @param {Array} array The array to inspect.
* @returns {Array} Returns the new array of placeholder indexes.
*/
function getHolders(array, placeholder) {
var index = -1,
length = array.length,
result = [];
while (++index < length) {
if (array[index] === placeholder) {
result.push(index);
}
}
return result;
}
/** /**
* Gets the appropriate "indexOf" function. If the `_.indexOf` method is * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
* customized this function returns the custom method, otherwise it returns * customized this function returns the custom method, otherwise it returns
@@ -2984,6 +2939,29 @@
}; };
} }
/**
* Replaces all `placeholder` elements in `array` with an internal placeholder
* and returns an array of their indexes.
*
* @private
* @param {Array} array The array to modify.
* @param {*} placeholder The placeholder to replace.
* @returns {Array} Returns the new array of placeholder indexes.
*/
function replaceHolders(array, placeholder) {
var index = -1,
length = array.length,
result = [];
while (++index < length) {
if (array[index] === placeholder) {
array[index] = PLACEHOLDER;
result.push(index);
}
}
return result;
}
/** /**
* Sets wrapper metadata on a given function. * Sets wrapper metadata on a given function.
* *
@@ -5701,7 +5679,7 @@
return createWrapper([func, BIND_FLAG, null, thisArg]); return createWrapper([func, BIND_FLAG, null, thisArg]);
} }
var args = slice(arguments, 2), var args = slice(arguments, 2),
partialHolders = getHolders(args, bind.placeholder); partialHolders = replaceHolders(args, bind.placeholder);
return basePartial(func, BIND_FLAG | PARTIAL_FLAG, args, partialHolders, thisArg); return basePartial(func, BIND_FLAG | PARTIAL_FLAG, args, partialHolders, thisArg);
} }
@@ -5779,7 +5757,7 @@
var data = [key, BIND_FLAG | BIND_KEY_FLAG, null, object]; var data = [key, BIND_FLAG | BIND_KEY_FLAG, null, object];
if (arguments.length > 2) { if (arguments.length > 2) {
var args = slice(arguments, 2); var args = slice(arguments, 2);
data.push(args, getHolders(args, bindKey.placeholder)); data.push(args, replaceHolders(args, bindKey.placeholder));
} }
return createWrapper(data); return createWrapper(data);
} }
@@ -6254,7 +6232,7 @@
*/ */
function partial(func) { function partial(func) {
var args = slice(arguments, 1), var args = slice(arguments, 1),
partialHolders = getHolders(args, partial.placeholder); partialHolders = replaceHolders(args, partial.placeholder);
return basePartial(func, PARTIAL_FLAG, args, partialHolders); return basePartial(func, PARTIAL_FLAG, args, partialHolders);
} }
@@ -6292,7 +6270,7 @@
*/ */
function partialRight(func) { function partialRight(func) {
var args = slice(arguments, 1), var args = slice(arguments, 1),
partialHolders = getHolders(args, partialRight.placeholder); partialHolders = replaceHolders(args, partialRight.placeholder);
return basePartial(func, PARTIAL_RIGHT_FLAG, args, partialHolders); return basePartial(func, PARTIAL_RIGHT_FLAG, args, partialHolders);
} }

View File

@@ -8111,21 +8111,21 @@
var a = _.bindKey(object, 'fn', ph2, 2), var a = _.bindKey(object, 'fn', ph2, 2),
b = _.partialRight(a, ph4, 6), b = _.partialRight(a, ph4, 6),
c = _.partial(b, ph3, 4); c = _.partial(b, 1, ph3, 4);
deepEqual(c(1, 3, 5), expected); deepEqual(c(3, 5), expected);
a = _.bind(fn, object, ph1, 2); a = _.bind(fn, object, ph1, 2);
b = _.partialRight(a, ph4, 6); b = _.partialRight(a, ph4, 6);
c = _.partial(b, ph3, 4); c = _.partial(b, 1, ph3, 4);
deepEqual(c(1, 3, 5), expected); deepEqual(c(3, 5), expected);
a = _.partial(fn, ph3, 2) a = _.partial(fn, ph3, 2)
b = _.bind(a, object, ph1, 4); b = _.bind(a, object, 1, ph1, 4);
c = _.partialRight(b, ph4, 6); c = _.partialRight(b, ph4, 6);
deepEqual(c(1, 3, 5), expected); deepEqual(c(3, 5), expected);
}); });
test('combinations of functions with overlaping placeholders should work', 3, function() { test('combinations of functions with overlaping placeholders should work', 3, function() {
@@ -8133,26 +8133,26 @@
return slice.call(arguments); return slice.call(arguments);
} }
var expected = [1, 2, 3, 4, 5], var expected = [1, 2, 3, 4],
object = { 'fn': fn }; object = { 'fn': fn };
var a = _.bindKey(object, 'fn', ph2, 2), var a = _.bindKey(object, 'fn', ph2, 2),
b = _.partialRight(a, ph4, 5), b = _.partialRight(a, ph4, 4),
c = _.partial(b, ph3, 4); c = _.partial(b, ph3, 3);
deepEqual(c(1, 3), expected); deepEqual(c(1), expected);
a = _.bind(fn, object, ph1, 2); a = _.bind(fn, object, ph1, 2);
b = _.partialRight(a, ph4, 5); b = _.partialRight(a, ph4, 4);
c = _.partial(b, ph3, 4); c = _.partial(b, ph3, 3);
deepEqual(c(1, 3), expected); deepEqual(c(1), expected);
a = _.partial(fn, ph3, 2) a = _.partial(fn, ph3, 2)
b = _.bind(a, object, ph1, 4); b = _.bind(a, object, ph1, 3);
c = _.partialRight(b, ph4, 5); c = _.partialRight(b, ph4, 4);
deepEqual(c(1, 3), expected); deepEqual(c(1), expected);
}); });
test('recursively bound functions should work', 1, function() { test('recursively bound functions should work', 1, function() {