Add better _.forIn support for legacy browsers.

Former-commit-id: a03ce4662021d6ac8ca12c4885a9c4718c227a30
This commit is contained in:
John-David Dalton
2013-05-14 09:04:15 -07:00
parent d3df072a22
commit d76ce85327
3 changed files with 67 additions and 28 deletions

View File

@@ -1148,6 +1148,27 @@
return source;
}
/**
* Removes all `support.enumErrorProps` references from `source`.
*
* @private
* @param {String} source The source to process.
* @returns {String} Returns the modified source.
*/
function removeSupportEnumErrorProps(source) {
source = removeSupportProp(source, 'enumErrorProps');
// remove `support.enumErrorProps` from `iteratorTemplate`
source = source.replace(getIteratorTemplate(source), function(match) {
return match
.replace(/(?: *\/\/.*\n)* *["'] *(?:<% *)?if *\(support\.enumErrorProps *(?:&&|\))(.+?}["']|[\s\S]+?<% *} *(?:%>|["'])).+/g, '')
.replace(/support\.enumErrorProps\s*\|\|\s*/g, '');
});
return source;
}
/**
* Removes all `support.enumPrototypes` references from `source`.
*
@@ -1168,7 +1189,7 @@
// remove `support.enumPrototypes` from `iteratorTemplate`
source = source.replace(getIteratorTemplate(source), function(match) {
return match
.replace(/(?: *\/\/.*\n)* *["'] *(?:<% *)?if *\(support\.enumPrototypes *(?:&&|\))[\s\S]+?<% *} *(?:%>|["']).+/g, '')
.replace(/(?: *\/\/.*\n)* *["'] *(?:<% *)?if *\(support\.enumPrototypes *(?:&&|\))(.+?}["']|[\s\S]+?<% *} *(?:%>|["'])).+/g, '')
.replace(/support\.enumPrototypes\s*\|\|\s*/g, '');
});
@@ -1249,7 +1270,9 @@
// remove `support.nonEnumShadows` from `iteratorTemplate`
source = source.replace(getIteratorTemplate(source), function(match) {
return match.replace(/(?: *\/\/.*\n)* *["']( *)<% *if *\(support\.nonEnumShadows[\s\S]+?["']\1<% *} *%>.+/, '');
return match
.replace(/\s*\|\|\s*support\.nonEnumShadows/, '')
.replace(/(?: *\/\/.*\n)* *["']( *)<% *if *\(support\.nonEnumShadows[\s\S]+?["']\1<% *} *%>.+/, '');
});
return source;
@@ -1986,6 +2009,7 @@
source = removeSupportNodeClass(source);
if (!isMobile) {
source = removeSupportEnumErrorProps(source);
source = removeSupportEnumPrototypes(source);
source = removeSupportNonEnumArgs(source);

View File

@@ -13,6 +13,7 @@
'callback',
'className',
'collection',
'conditions',
'ctor',
'ctorByClass',
'errorClass',
@@ -36,8 +37,8 @@
'objectTypes',
'ownIndex',
'ownProps',
'proto',
'result',
'skipErrorProps',
'skipProto',
'source',
'stringClass',
@@ -112,6 +113,7 @@
'difference',
'drop',
'each',
'enumErrorProps',
'enumPrototypes',
'environment',
'escape',
@@ -290,7 +292,7 @@
string = string.slice(left.length);
}
// avoids removing the '\n' of the `stringEscapes` object
string = string.replace(/\[object |delete |else (?!{)|function | in |return\s+[\w"']|throw |typeof |use strict|var |@ |(["'])\\n\1|\\\\n|\\n|\s+/g, function(match) {
string = string.replace(/\[object |delete |else (?!{)|function | in | instanceof |return\s+[\w"']|throw |typeof |use strict|var |@ |(["'])\\n\1|\\\\n|\\n|\s+/g, function(match) {
return match == false || match == '\\n' ? '' : match;
});
// unclip

View File

@@ -191,6 +191,7 @@
getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
hasOwnProperty = objectProto.hasOwnProperty,
push = arrayProto.push,
propertyIsEnumerable = objectProto.propertyIsEnumerable,
setImmediate = context.setImmediate,
setTimeout = context.setTimeout,
toString = objectProto.toString;
@@ -346,6 +347,14 @@
*/
support.argsClass = isArguments(arguments);
/**
* Detect if `name` or `message` properties of `Error.prototype` are
* enumerable by default. (IE < 9, Safari < 5.1)
*
* @type Boolean
*/
support.enumErrorProps = propertyIsEnumerable.call(errorProto, 'message') || propertyIsEnumerable.call(errorProto, 'name');
/**
* Detect if `prototype` properties are enumerable by default.
*
@@ -357,7 +366,7 @@
* @memberOf _.support
* @type Boolean
*/
support.enumPrototypes = ctor.propertyIsEnumerable('prototype');
support.enumPrototypes = propertyIsEnumerable.call(ctor, 'prototype');
/**
* Detect if `Function#bind` exists and is inferred to be fast (all but V8).
@@ -529,7 +538,7 @@
// iterate over the array-like value
' while (++index < length) {\n' +
' <%= loop %>\n' +
' <%= loop %>;\n' +
' }\n' +
'}\n' +
'else {' +
@@ -541,7 +550,7 @@
' if (length && isArguments(iterable)) {\n' +
' while (++index < length) {\n' +
" index += '';\n" +
' <%= loop %>\n' +
' <%= loop %>;\n' +
' }\n' +
' } else {' +
' <% } %>' +
@@ -551,29 +560,37 @@
" var skipProto = typeof iterable == 'function';\n" +
' <% } %>' +
// iterate own properties using `Object.keys` if it's fast
// avoid iterating over `Error.prototype` properties in older IE and Safari
' <% if (support.enumErrorProps || support.nonEnumShadows) { %>\n' +
' var skipErrorProps = iterable === errorProto || iterable instanceof Error;\n' +
' <% } %>' +
// define conditions used in the loop
' <%' +
' var conditions = [];' +
' if (support.enumPrototypes) { conditions.push("!(skipProto && index == \'prototype\')"); }' +
' if (support.enumErrorProps) { conditions.push("!(skipErrorProps && (index == \'message\' || index == \'name\'))"); }' +
' %>' +
// iterate own properties using `Object.keys`
' <% if (useHas && useKeys) { %>\n' +
' var ownIndex = -1,\n' +
' ownProps = objectTypes[typeof iterable] ? keys(iterable) : [],\n' +
' length = ownProps.length;\n\n' +
' while (++ownIndex < length) {\n' +
' index = ownProps[ownIndex];\n' +
" <% if (support.enumPrototypes) { %>if (!(skipProto && index == 'prototype')) {\n <% } %>" +
' <%= loop %>\n' +
' <% if (support.enumPrototypes) { %>}\n<% } %>' +
' index = ownProps[ownIndex];\n<%' +
" if (conditions.length) { %> if (<%= conditions.join(' && ') %>) {\n <% } %>" +
' <%= loop %>;' +
' <% if (conditions.length) { %>\n }<% } %>\n' +
' }' +
// else using a for-in loop
' <% } else { %>\n' +
' for (index in iterable) {<%' +
' if (support.enumPrototypes || useHas) { %>\n if (<%' +
" if (support.enumPrototypes) { %>!(skipProto && index == 'prototype')<% }" +
' if (support.enumPrototypes && useHas) { %> && <% }' +
' if (useHas) { %>hasOwnProperty.call(iterable, index)<% }' +
' %>) {' +
' <% } %>\n' +
' for (index in iterable) {\n<%' +
' if (useHas) { conditions.push("hasOwnProperty.call(iterable, index)"); }' +
" if (conditions.length) { %> if (<%= conditions.join(' && ') %>) {\n <% } %>" +
' <%= loop %>;' +
' <% if (support.enumPrototypes || useHas) { %>\n }<% } %>\n' +
' <% if (conditions.length) { %>\n }<% } %>\n' +
' }' +
// Because IE < 9 can't set the `[[Enumerable]]` attribute of an
@@ -583,19 +600,15 @@
' <% if (support.nonEnumShadows) { %>\n\n' +
' if (iterable !== objectProto) {\n' +
" var ctor = iterable.constructor,\n" +
' proto = ctor && ctor.prototype,\n' +
' isProto = iterable === proto,\n' +
' nonEnum = nonEnumProps[objectClass];\n\n' +
' if (isProto) {\n' +
" var className = iterable === stringProto ? stringClass : iterable === errorProto ? errorClass : toString.call(iterable),\n" +
' nonEnum = nonEnumProps[iterable === (ctorByClass[className] && ctorByClass[className].prototype) ? className : objectClass];\n' +
' }\n' +
' isProto = iterable === (ctor && ctor.prototype),\n' +
' className = iterable === stringProto ? stringClass : iterable === errorProto ? errorClass : toString.call(iterable),\n' +
' nonEnum = nonEnumProps[className];\n' +
' <% for (k = 0; k < 7; k++) { %>\n' +
" index = '<%= shadowedProps[k] %>';\n" +
' if ((!(isProto && nonEnum[index]) && hasOwnProperty.call(iterable, index))<%' +
' if (!useHas) { %> || (!nonEnum[index] && iterable[index] !== objectProto[index])<% }' +
' %>) {\n' +
' <%= loop %>\n' +
' <%= loop %>;\n' +
' }' +
' <% } %>\n' +
' }' +