Clarify browsers affected by nonEnumArgs and reduce code around hasEnumPrototype.

Former-commit-id: 587f755332accbca26dc1eb357a66d4f898aad88
This commit is contained in:
John-David Dalton
2013-02-04 23:55:52 -08:00
parent d87929d61c
commit 7b918f77a9
3 changed files with 44 additions and 34 deletions

View File

@@ -805,29 +805,24 @@
// match multi-line comment block (could be on a single line) // match multi-line comment block (could be on a single line)
'(?:\\n +/\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/\\n)?' + '(?:\\n +/\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/\\n)?' +
// begin non-capturing group // begin non-capturing group
'(?:' + '( *)(?:' +
// match a function declaration // match a function declaration
'( *)function ' + funcName + '\\b[\\s\\S]+?\\n\\1}|' + 'function ' + funcName + '\\b[\\s\\S]+?\\n\\1}|' +
// match a variable declaration with `createIterator`
' +var ' + funcName + ' *=.*?createIterator\\((?:{|[a-zA-Z])[\\s\\S]+?\\);|' +
// match a variable declaration with function expression // match a variable declaration with function expression
'( *)var ' + funcName + ' *=.*?function[\\s\\S]+?\\n\\2};' + 'var ' + funcName + ' *=.*?function[\\s\\S]+?\\n\\1};' +
// end non-capturing group // end non-capturing group
')\\n' ')\\n'
)); ));
if (result) {
return result[0];
}
// match variables that are explicitly defined as functions // match variables that are explicitly defined as functions
result = source.match(RegExp( result || (result = source.match(RegExp(
// match multi-line comment block // match multi-line comment block
'(?:\\n +/\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/)?\\n' + '(?:\\n +/\\*[^*]*\\*+(?:[^/][^*]*\\*+)*/)?\\n' +
// match a simple variable declaration // match simple variable declarations and those with `createIterator`
' *var ' + funcName + ' *=.+?;\\n' ' *var ' + funcName + ' *=(?:.+?|.*?createIterator\\([\\s\\S]+?\\));\\n'
)); )));
return /@type +Function/.test(result) ? result[0] : ''; return /@type +Function|function\s*\w*\(/.test(result) ? result[0] : '';
} }
/** /**
@@ -953,12 +948,12 @@
source = removeFromCreateIterator(source, 'shadowed'); source = removeFromCreateIterator(source, 'shadowed');
// remove `hasDontEnumBug` declaration and assignment // remove `hasDontEnumBug` declaration and assignment
source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasDontEnumBug;|.+?hasDontEnumBug *=.+/g, ''); source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasDontEnumBug\b.*|.+?hasDontEnumBug *=.+/g, '');
// remove `shadowed` variable // remove `shadowed` variable
source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var shadowed[\s\S]+?;\n/, ''); source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var shadowed[\s\S]+?;\n/, '');
// remove JScript `[[DontEnum]]` fix from `iteratorTemplate` // remove `hasDontEnumBug` from `iteratorTemplate`
source = source.replace(getIteratorTemplate(source), function(match) { source = source.replace(getIteratorTemplate(source), function(match) {
return match.replace(/(?: *\/\/.*\n)* *["']( *)<% *if *\(hasDontEnumBug[\s\S]+?["']\1<% *} *%>.+/, ''); return match.replace(/(?: *\/\/.*\n)* *["']( *)<% *if *\(hasDontEnumBug[\s\S]+?["']\1<% *} *%>.+/, '');
}); });
@@ -977,14 +972,16 @@
source = removeFromCreateIterator(source, 'hasEnumPrototype'); source = removeFromCreateIterator(source, 'hasEnumPrototype');
// remove `hasEnumPrototype` declaration and assignment // remove `hasEnumPrototype` declaration and assignment
source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasEnumPrototype;|.+?hasEnumPrototype *=.+/g, ''); source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var hasEnumPrototype\b.*|.+?hasEnumPrototype *=.+/g, '');
// remove `prototype` [[Enumerable]] fix from `_.keys` // remove `hasEnumPrototype` from `_.keys`
source = source.replace(matchFunction(source, 'keys'), function(match) { source = source.replace(matchFunction(source, 'keys'), function(match) {
return match.replace(/(?:\s*\/\/.*)*(\s*return *).+?propertyIsEnumerable[\s\S]+?: */, '$1'); return match
.replace(/\(hasEnumPrototype[^)]+\)(?:\s*\|\|\s*)?/, '')
.replace(/\s*if *\(\s*\)[^}]+}/, '');
}); });
// remove `prototype` [[Enumerable]] fix from `iteratorTemplate` // remove `hasEnumPrototype` from `iteratorTemplate`
source = source.replace(getIteratorTemplate(source), function(match) { source = source.replace(getIteratorTemplate(source), function(match) {
return match return match
.replace(/(?: *\/\/.*\n)* *["'] *(?:<% *)?if *\(hasEnumPrototype *(?:&&|\))[\s\S]+?<% *} *(?:%>|["']).+/g, '') .replace(/(?: *\/\/.*\n)* *["'] *(?:<% *)?if *\(hasEnumPrototype *(?:&&|\))[\s\S]+?<% *} *(?:%>|["']).+/g, '')
@@ -1025,7 +1022,7 @@
*/ */
function removeIteratesOwnLast(source) { function removeIteratesOwnLast(source) {
// remove `iteratesOwnLast` declaration and assignment // remove `iteratesOwnLast` declaration and assignment
source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var iteratesOwnLast;|.+?iteratesOwnLast *=.+/g, ''); source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var iteratesOwnLast\b.*|.+?iteratesOwnLast *=.+/g, '');
// remove `iteratesOwnLast` from `shimIsPlainObject` // remove `iteratesOwnLast` from `shimIsPlainObject`
source = source.replace(matchFunction(source, 'shimIsPlainObject'), function(match) { source = source.replace(matchFunction(source, 'shimIsPlainObject'), function(match) {
@@ -1117,9 +1114,16 @@
source = removeFromCreateIterator(source, 'nonEnumArgs'); source = removeFromCreateIterator(source, 'nonEnumArgs');
// remove `nonEnumArgs` declaration and assignment // remove `nonEnumArgs` declaration and assignment
source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var nonEnumArgs;|.+?nonEnumArgs *=.+/g, ''); source = source.replace(/(?:\n +\/\*[^*]*\*+(?:[^\/][^*]*\*+)*\/)?\n *var nonEnumArgs\b.*|.+?nonEnumArgs *=.+/g, '');
// remove `nonEnumArgs` fix from `iteratorTemplate` // remove `nonEnumArgs` from `_.keys`
source = source.replace(matchFunction(source, 'keys'), function(match) {
return match
.replace(/(?:\s*\|\|\s*)?\(nonEnumArgs[^)]+\)\)/, '')
.replace(/\s*if *\(\s*\)[^}]+}/, '');
});
// remove `nonEnumArgs` from `iteratorTemplate`
source = source.replace(getIteratorTemplate(source), function(match) { source = source.replace(getIteratorTemplate(source), function(match) {
return match return match
.replace(/(?: *\/\/.*\n)*( *["'] *)<% *} *else *if *\(nonEnumArgs[\s\S]+?(\1<% *} *%>.+)/, '$2') .replace(/(?: *\/\/.*\n)*( *["'] *)<% *} *else *if *\(nonEnumArgs[\s\S]+?(\1<% *} *%>.+)/, '$2')

View File

@@ -26,7 +26,6 @@
'objectTypes', 'objectTypes',
'ownIndex', 'ownIndex',
'ownProps', 'ownProps',
'propertyIsEnumerable',
'result', 'result',
'skipProto', 'skipProto',
'source', 'source',

View File

@@ -85,7 +85,6 @@
getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf, getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
hasOwnProperty = objectRef.hasOwnProperty, hasOwnProperty = objectRef.hasOwnProperty,
push = arrayRef.push, push = arrayRef.push,
propertyIsEnumerable = objectRef.propertyIsEnumerable,
toString = objectRef.toString; toString = objectRef.toString;
/* Native method shortcuts for methods with the same name as other `lodash` methods */ /* Native method shortcuts for methods with the same name as other `lodash` methods */
@@ -153,7 +152,7 @@
var hasObjectSpliceBug = (hasObjectSpliceBug = { '0': 1, 'length': 1 }, var hasObjectSpliceBug = (hasObjectSpliceBug = { '0': 1, 'length': 1 },
arrayRef.splice.call(hasObjectSpliceBug, 0, 1), hasObjectSpliceBug[0]); arrayRef.splice.call(hasObjectSpliceBug, 0, 1), hasObjectSpliceBug[0]);
/** Detect if an `arguments` object's indexes are non-enumerable (IE < 9) */ /** Detect if `arguments` object indexes are non-enumerable (Firefox < 4, IE < 9, Safari < 5.1) */
var nonEnumArgs = true; var nonEnumArgs = true;
(function() { (function() {
@@ -164,7 +163,7 @@
for (prop in arguments) { nonEnumArgs = !prop; } for (prop in arguments) { nonEnumArgs = !prop; }
hasDontEnumBug = !/valueOf/.test(props); hasDontEnumBug = !/valueOf/.test(props);
hasEnumPrototype = propertyIsEnumerable.call(ctor, 'prototype'); hasEnumPrototype = ctor.propertyIsEnumerable('prototype');
iteratesOwnLast = props[0] != 'x'; iteratesOwnLast = props[0] != 'x';
}(1)); }(1));
@@ -392,8 +391,7 @@
// avoid iterating over `prototype` properties in older Firefox, Opera, and Safari // avoid iterating over `prototype` properties in older Firefox, Opera, and Safari
' <% if (hasEnumPrototype) { %>\n' + ' <% if (hasEnumPrototype) { %>\n' +
" var skipProto = typeof iterable == 'function' && \n" + " var skipProto = typeof iterable == 'function';\n" +
" propertyIsEnumerable.call(iterable, 'prototype');\n" +
' <% } %>' + ' <% } %>' +
// iterate own properties using `Object.keys` if it's fast // iterate own properties using `Object.keys` if it's fast
@@ -710,13 +708,13 @@
// create the function factory // create the function factory
var factory = Function( var factory = Function(
'createCallback, hasOwnProperty, isArguments, isArray, isString, ' + 'createCallback, hasOwnProperty, isArguments, isArray, isString, ' +
'objectTypes, nativeKeys, propertyIsEnumerable', 'objectTypes, nativeKeys',
'return function(' + args + ') {\n' + iteratorTemplate(data) + '\n}' 'return function(' + args + ') {\n' + iteratorTemplate(data) + '\n}'
); );
// return the compiled function // return the compiled function
return factory( return factory(
createCallback, hasOwnProperty, isArguments, isArray, isString, createCallback, hasOwnProperty, isArguments, isArray, isString,
objectTypes, nativeKeys, propertyIsEnumerable objectTypes, nativeKeys
); );
} }
@@ -728,6 +726,7 @@
* iteration early by explicitly returning `false`. * iteration early by explicitly returning `false`.
* *
* @private * @private
* @type Function
* @param {Array|Object|String} collection The collection to iterate over. * @param {Array|Object|String} collection The collection to iterate over.
* @param {Function} [callback=identity] The function called per iteration. * @param {Function} [callback=identity] The function called per iteration.
* @param {Mixed} [thisArg] The `this` binding of `callback`. * @param {Mixed} [thisArg] The `this` binding of `callback`.
@@ -855,6 +854,7 @@
* *
* @static * @static
* @memberOf _ * @memberOf _
* @type Function
* @category Objects * @category Objects
* @param {Object} object The object to iterate over. * @param {Object} object The object to iterate over.
* @param {Function} [callback=identity] The function called per iteration. * @param {Function} [callback=identity] The function called per iteration.
@@ -887,6 +887,7 @@
* *
* @static * @static
* @memberOf _ * @memberOf _
* @type Function
* @category Objects * @category Objects
* @param {Object} object The object to iterate over. * @param {Object} object The object to iterate over.
* @param {Function} [callback=identity] The function called per iteration. * @param {Function} [callback=identity] The function called per iteration.
@@ -937,10 +938,14 @@
* // => ['one', 'two', 'three'] (order is not guaranteed) * // => ['one', 'two', 'three'] (order is not guaranteed)
*/ */
var keys = !nativeKeys ? shimKeys : function(object) { var keys = !nativeKeys ? shimKeys : function(object) {
// avoid iterating over the `prototype` property if (!isObject(object)) {
return hasEnumPrototype && typeof object == 'function' && propertyIsEnumerable.call(object, 'prototype') return [];
? shimKeys(object) }
: (isObject(object) ? nativeKeys(object) : []); if ((hasEnumPrototype && typeof object == 'function') ||
(nonEnumArgs && object.length && isArguments(object))) {
return shimKeys(object);
}
return nativeKeys(object);
}; };
/** /**
@@ -1027,6 +1032,7 @@
* *
* @static * @static
* @memberOf _ * @memberOf _
* @type Function
* @alias extend * @alias extend
* @category Objects * @category Objects
* @param {Object} object The destination object. * @param {Object} object The destination object.
@@ -1220,6 +1226,7 @@
* *
* @static * @static
* @memberOf _ * @memberOf _
* @type Function
* @category Objects * @category Objects
* @param {Object} object The destination object. * @param {Object} object The destination object.
* @param {Object} [source1, source2, ...] The source objects. * @param {Object} [source1, source2, ...] The source objects.