Make breakIndicator use expando in underscore builds.

This commit is contained in:
John-David Dalton
2014-01-21 19:59:59 -08:00
parent eba85e1ec3
commit a249b315ca
2 changed files with 214 additions and 79 deletions

View File

@@ -12,13 +12,7 @@
/** Used as a safe reference for `undefined` in pre ES5 environments */
var undefined;
/** Used to generate unique IDs */
var idCounter = 0;
/** Used by methods to exit iteration */
var breakIndicator = '__lodash_break_1335248838000__';
/** Used to compose bitmasks for `__bindData__` */
/** Used to compose bitmasks for wrapper metadata */
var BIND_FLAG = 1,
BIND_KEY_FLAG = 2,
CURRY_FLAG = 4,
@@ -26,6 +20,18 @@
PARTIAL_FLAG = 16,
PARTIAL_RIGHT_FLAG = 32;
/** Used as the semantic version number */
var version = '2.4.1';
/** Used as the property name for wrapper metadata */
var expando = '__lodash@' + version + '__';
/** Used by methods to exit iteration */
var breakIndicator = expando + 'breaker__';
/** Used to generate unique IDs */
var idCounter = 0;
/** Used to match HTML entities and HTML characters */
var reEscapedHtml = /&(?:amp|lt|gt|quot|#x27);/g,
reUnescapedHtml = /[&<>"']/g;
@@ -35,9 +41,15 @@
reEvaluate = /<%([\s\S]+?)%>/g,
reInterpolate = /<%=([\s\S]+?)%>/g;
/** Used to detected named functions */
var reFuncName = /^\s*function[ \n\r\t]+\w/;
/** Used to ensure capturing order of template delimiters */
var reNoMatch = /($^)/;
/** Used to detect functions containing a `this` reference */
var reThis = /\bthis\b/;
/** Used to match unescaped characters in compiled string literals */
var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
@@ -52,6 +64,14 @@
regexpClass = '[object RegExp]',
stringClass = '[object String]';
/** Used as the property descriptor for wrapper metadata */
var descriptor = {
'configurable': false,
'enumerable': false,
'value': null,
'writable': false
};
/**
* Used to convert characters to HTML entities:
*
@@ -229,7 +249,19 @@
hasOwnProperty = objectProto.hasOwnProperty,
push = arrayRef.push,
propertyIsEnumerable = objectProto.propertyIsEnumerable,
splice = arrayRef.splice;
splice = arrayRef.splice,
unshift = arrayRef.unshift;
/** Used to set meta data on functions */
var defineProperty = (function() {
// IE 8 only accepts DOM elements
try {
var o = {},
func = isNative(func = Object.defineProperty) && func,
result = func(o, o, o) && func;
} catch(e) { }
return result;
}());
/* Native method shortcuts for methods with the same name as other `lodash` methods */
var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate,
@@ -410,13 +442,13 @@
* sets its meta data.
*
* @private
* @param {Array} bindData The bind data array.
* @param {Array} data The metadata array.
* @returns {Function} Returns the new bound function.
*/
function baseBind(bindData) {
var func = bindData[0],
partialArgs = bindData[2],
thisArg = bindData[4];
function baseBind(data) {
var func = data[0],
thisArg = data[3],
partialArgs = data[4];
function bound() {
// `Function#bind` spec
@@ -438,6 +470,7 @@
}
return func.apply(thisArg, args || arguments);
}
setData(bound, data);
return bound;
}
@@ -485,6 +518,28 @@
if (typeof thisArg == 'undefined' || !('prototype' in func)) {
return func;
}
var data = func[expando];
if (typeof data == 'undefined') {
if (support.funcNames) {
data = !func.name;
}
data = data || !support.funcDecomp;
if (!data) {
var source = fnToString.call(func);
if (!support.funcNames) {
data = !reFuncName.test(source);
}
if (!data) {
// checks if `func` references the `this` keyword and stores the result
data = reThis.test(source);
setData(func, data);
}
}
}
// exit early if there are no `this` references or `func` is bound
if (data === false || (data !== true && data[1] & BIND_FLAG)) {
return func;
}
switch (argCount) {
case 1: return function(value) {
return func.call(thisArg, value);
@@ -507,16 +562,16 @@
* sets its meta data.
*
* @private
* @param {Array} bindData The bind data array.
* @param {Array} data The metadata array.
* @returns {Function} Returns the new function.
*/
function baseCreateWrapper(bindData) {
var func = bindData[0],
bitmask = bindData[1],
partialArgs = bindData[2],
partialRightArgs = bindData[3],
thisArg = bindData[4],
arity = bindData[5];
function baseCreateWrapper(data) {
var func = data[0],
bitmask = data[1],
arity = data[2],
thisArg = data[3],
partialArgs = data[4],
partialRightArgs = data[5];
var isBind = bitmask & BIND_FLAG,
isBindKey = bitmask & BIND_KEY_FLAG,
@@ -535,10 +590,15 @@
if (partialRightArgs) {
push.apply(args, partialRightArgs);
}
if (isCurry && args.length < arity) {
var argsLength = arguments.length;
if (isCurry && argsLength < arity) {
bitmask |= PARTIAL_FLAG;
bitmask &= ~PARTIAL_RIGHT_FLAG;
return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~(BIND_FLAG | BIND_KEY_FLAG)), args, null, thisArg, arity]);
bitmask &= ~PARTIAL_RIGHT_FLAG
if (!isCurryBound) {
bitmask &= ~(BIND_FLAG | BIND_KEY_FLAG);
}
var newArity = nativeMax(0, arity - argsLength);
return baseCreateWrapper([func, bitmask, newArity, thisArg, args]);
}
}
args || (args = arguments);
@@ -552,6 +612,7 @@
}
return func.apply(thisBinding, args);
}
setData(bound, data);
return bound;
}
@@ -879,25 +940,23 @@
* @param {Function|string} func The function or method name to reference.
* @param {number} bitmask The bitmask of flags to compose.
* The bitmask may be composed of the following flags:
* 1 - `_.bind`
* 2 - `_.bindKey`
* 4 - `_.curry`
* 8 - `_.curry` (bound)
* 1 - `_.bind`
* 2 - `_.bindKey`
* 4 - `_.curry`
* 8 - `_.curry` (bound)
* 16 - `_.partial`
* 32 - `_.partialRight`
* @param {number} [arity] The arity of `func`.
* @param {*} [thisArg] The `this` binding of `func`.
* @param {Array} [partialArgs] An array of arguments to prepend to those
* provided to the new function.
* @param {Array} [partialRightArgs] An array of arguments to append to those
* provided to the new function.
* @param {*} [thisArg] The `this` binding of `func`.
* @param {number} [arity] The arity of `func`.
* @returns {Function} Returns the new function.
*/
function createWrapper(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) {
function createWrapper(func, bitmask, arity, thisArg, partialArgs, partialRightArgs) {
var isBind = bitmask & BIND_FLAG,
isBindKey = bitmask & BIND_KEY_FLAG,
isCurry = bitmask & CURRY_FLAG,
isCurryBound = bitmask & CURRY_BOUND_FLAG,
isPartial = bitmask & PARTIAL_FLAG,
isPartialRight = bitmask & PARTIAL_RIGHT_FLAG;
@@ -905,16 +964,69 @@
throw new TypeError;
}
if (isPartial && !partialArgs.length) {
bitmask &= ~16;
bitmask &= ~PARTIAL_FLAG;
isPartial = partialArgs = false;
}
if (isPartialRight && !partialRightArgs.length) {
bitmask &= ~32;
bitmask &= ~PARTIAL_RIGHT_FLAG;
isPartialRight = partialRightArgs = false;
}
var data = !isBindKey && func[expando];
if (data && data !== true) {
// shallow clone `data`
data = slice(data);
// clone partial left arguments
if (data[4]) {
data[4] = slice(data[4]);
}
// clone partial right arguments
if (data[5]) {
data[5] = slice(data[5]);
}
// set arity if provided
if (typeof arity == 'number') {
data[2] = arity;
}
// set `thisArg` if not previously bound
var bound = data[1] & BIND_FLAG;
if (isBind && !bound) {
data[3] = thisArg;
}
// set if currying a bound function
if (!isBind && bound) {
bitmask |= CURRY_BOUND_FLAG;
}
// append partial left arguments
if (isPartial) {
if (data[4]) {
push.apply(data[4], partialArgs);
} else {
data[4] = partialArgs;
}
}
// prepend partial right arguments
if (isPartialRight) {
if (data[5]) {
unshift.apply(data[5], partialRightArgs);
} else {
data[5] = partialRightArgs;
}
}
// merge flags
data[1] |= bitmask;
return createWrapper.apply(null, data);
}
if (arity == null) {
arity = isBindKey ? 0 : func.length;
} else if (arity < 0) {
arity = 0;
}
// fast path for `_.bind`
var creater = (bitmask == BIND_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG)) ? baseBind : baseCreateWrapper;
return creater([func, bitmask, partialArgs, partialRightArgs, thisArg, arity]);
data = [func, bitmask, arity, thisArg, partialArgs, partialRightArgs];
return (bitmask == BIND_FLAG || bitmask == (BIND_FLAG | PARTIAL_FLAG))
? baseBind(data)
: baseCreateWrapper(data);
}
/**
@@ -941,6 +1053,18 @@
return typeof value == 'function' && reNative.test(fnToString.call(value));
}
/**
* Sets wrapper metadata on a given function.
*
* @private
* @param {Function} func The function to set data on.
* @param {Array} value The data array to set.
*/
var setData = !defineProperty ? noop : function(func, value) {
descriptor.value = value;
defineProperty(func, expando, descriptor);
};
/*--------------------------------------------------------------------------*/
/**
@@ -3156,9 +3280,14 @@
* // => 'hi fred'
*/
function bind(func, thisArg) {
return arguments.length > 2
? createWrapper(func, BIND_FLAG | PARTIAL_FLAG, slice(arguments, 2), null, thisArg)
: createWrapper(func, BIND_FLAG, null, null, thisArg);
if (arguments.length < 3) {
return createWrapper(func, BIND_FLAG, null, thisArg);
}
var arity = func && (func[expando] ? func[expando][2] : func.length),
partialArgs = slice(arguments, 2);
arity -= partialArgs.length;
return createWrapper(func, BIND_FLAG | PARTIAL_FLAG, arity, thisArg, partialArgs);
}
/**
@@ -3194,7 +3323,7 @@
while (++index < length) {
var key = funcs[index];
object[key] = createWrapper(object[key], BIND_FLAG, null, null, object);
object[key] = createWrapper(object[key], BIND_FLAG, null, object);
}
return object;
}
@@ -3542,7 +3671,11 @@
* // => 'hi fred'
*/
function partial(func) {
return createWrapper(func, PARTIAL_FLAG, slice(arguments, 1));
var arity = func && (func[expando] ? func[expando][2] : func.length),
partialArgs = slice(arguments, 1);
arity -= partialArgs.length;
return createWrapper(func, PARTIAL_FLAG, arity, null, partialArgs);
}
/**
@@ -3619,7 +3752,7 @@
* // => '<p>fred, barney, &amp; pebbles</p>'
*/
function wrap(value, wrapper) {
return createWrapper(wrapper, PARTIAL_FLAG, [value]);
return createWrapper(wrapper, PARTIAL_FLAG, null, null, [value]);
}
/*--------------------------------------------------------------------------*/
@@ -5071,7 +5204,7 @@
* @memberOf _
* @type string
*/
lodash.VERSION = '2.4.1';
lodash.VERSION = version;
// add "Chaining" functions to the wrapper
lodash.prototype.chain = wrapperChain;