mirror of
https://github.com/whoisclebs/lodash.git
synced 2026-01-31 15:27:50 +00:00
Optimize _.template when no evaluate delimiters are used and optimize _.bind when partially applied in V8.
Former-commit-id: 25489d41ba3cac7ac3f1414e09f1971a11a779be
This commit is contained in:
20
build.js
20
build.js
@@ -301,7 +301,7 @@
|
||||
* @returns {String} Returns the formatted source.
|
||||
*/
|
||||
function getFunctionSource(func) {
|
||||
var source = (func + '');
|
||||
var source = func.source || (func + '');
|
||||
return source.replace(/\n(?:.*)/g, function(match, index) {
|
||||
match = match.slice(1);
|
||||
return (
|
||||
@@ -465,19 +465,6 @@
|
||||
return removeFromCreateIterator(source, varName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes non-syntax critical whitespace from a string.
|
||||
*
|
||||
* @private
|
||||
* @param {String} source The source to process.
|
||||
* @returns {String} Returns the source with whitespace removed.
|
||||
*/
|
||||
function removeWhitespace(source) {
|
||||
return source.replace(/\[object |else if|function | in |return\s+[\w']|throw |typeof |var |@ |\\\\n|\\n|\s+/g, function(match) {
|
||||
return match == false || match == '\\n' ? '' : match;
|
||||
});
|
||||
}
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
// Backbone build
|
||||
@@ -720,8 +707,8 @@
|
||||
}
|
||||
else {
|
||||
// inline `iteratorTemplate` template
|
||||
source = source.replace(/(( +)var iteratorTemplate *= *)([\s\S]+?\n\2.+?);\n/, (function() {
|
||||
var code = getFunctionSource(lodash._iteratorTemplate.source);
|
||||
source = source.replace(/(( +)var iteratorTemplate *= *)[\s\S]+?\n\2.+?;\n/, (function() {
|
||||
var code = getFunctionSource(lodash._iteratorTemplate);
|
||||
|
||||
// expand properties to avoid having to use a with-statement
|
||||
iteratorOptions.forEach(function(property) {
|
||||
@@ -735,7 +722,6 @@
|
||||
.replace(/__p *\+= *' *';/g, '')
|
||||
.replace(/(__p *\+= *)' *' *\+/g, '$1')
|
||||
.replace(/\+\s*' *';/g, ';')
|
||||
.replace(/';(?:\\n|\s)*} *'/g, "'}'")
|
||||
.replace(/(\{) *;|; *(\})/g, '$1$2')
|
||||
.replace(/\(\(__t *= *\( *([^)]+) *\)\) *== *null *\? *'' *: *__t\)/g, '$1');
|
||||
|
||||
|
||||
@@ -207,7 +207,10 @@
|
||||
source = source.replace(RegExp('\\.(' + propWhitelist.join('|') + ')\\b', 'g'), "['$1']");
|
||||
|
||||
// remove brackets from `_.escape()` in `tokenizeEscape`
|
||||
source = source.replace("_['escape'](\"", '_.escape("');
|
||||
source = source.replace(/_\['escape']\("/, '_.escape("');
|
||||
|
||||
// remove brackets from `_.escape()` in `_.template`
|
||||
source = source.replace(/__e *= *_\['escape']/, '__e=_.escape');
|
||||
|
||||
// remove brackets from `result[length].value` in `_.sortBy`
|
||||
source = source.replace("result[length]['value']", 'result[length].value');
|
||||
@@ -220,6 +223,11 @@
|
||||
});
|
||||
});
|
||||
|
||||
// remove whitespace from `_.template` related regexpes
|
||||
source = source.replace(/(?:reEmptyString\w+|reInsertVariable) *=.+/g, function(match) {
|
||||
return match.replace(/ /g, '');
|
||||
});
|
||||
|
||||
// remove newline from double-quoted string in `_.template`
|
||||
source = source.replace('"\';\\n"', '"\';"');
|
||||
|
||||
|
||||
156
lodash.js
156
lodash.js
@@ -8,10 +8,21 @@
|
||||
;(function(window, undefined) {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Used to match potentially incorrect data object references, i.e. `obj.obj`,
|
||||
* in compiled templates. The variables are assigned in `_.template`.
|
||||
*/
|
||||
var lastVariable,
|
||||
reDoubleVariable;
|
||||
|
||||
/** Detect free variable `exports` */
|
||||
var freeExports = typeof exports == 'object' && exports &&
|
||||
(typeof global == 'object' && global && global == global.global && (window = global), exports);
|
||||
|
||||
/** Native prototype shortcuts */
|
||||
var ArrayProto = Array.prototype,
|
||||
ObjectProto = Object.prototype;
|
||||
|
||||
/**
|
||||
* Detect the JScript [[DontEnum]] bug:
|
||||
* In IE < 9 an objects own properties, shadowing non-enumerable ones, are
|
||||
@@ -25,10 +36,20 @@
|
||||
/** Used to restore the original `_` reference in `noConflict` */
|
||||
var oldDash = window._;
|
||||
|
||||
/** Used to match empty strings in compiled templates */
|
||||
var reEmptyStringEvaluate = /\b__p \+= '';/g,
|
||||
reEmptyStringInterpolate = /\b__p \+= '' \+/g,
|
||||
reEmptyStringHybrid = /\b__t\) \+\n'';/g;
|
||||
|
||||
/** Used to insert the data object variable into compiled templates */
|
||||
var reInsertVariable = /(?:__e|__t = )\(\s*(?![\s"']|this\.)/g;
|
||||
|
||||
/** Used to detect if a method is native */
|
||||
var reNative = RegExp('^' + ({}.valueOf + '')
|
||||
.replace(/[.*+?^=!:${}()|[\]\/\\]/g, '\\$&')
|
||||
.replace(/valueOf|for [^\]]+/g, '.+?') + '$');
|
||||
var reNative = RegExp('^' +
|
||||
(ObjectProto.valueOf + '')
|
||||
.replace(/[.*+?^=!:${}()|[\]\/\\]/g, '\\$&')
|
||||
.replace(/valueOf|for [^\]]+/g, '.+?') + '$'
|
||||
);
|
||||
|
||||
/** Used to match tokens in template text */
|
||||
var reToken = /__token__(\d+)/g;
|
||||
@@ -54,12 +75,41 @@
|
||||
/** Used to store tokenized template text snippets */
|
||||
var tokenized = [];
|
||||
|
||||
/* Detect if `Function#bind` exists and is inferred to be fast (i.e. all but V8) */
|
||||
var useNativeBind = nativeBind && /\n|Opera/.test(nativeBind + toString.call(window.opera));
|
||||
|
||||
/** Detect if sourceURL syntax is usable without erroring */
|
||||
try {
|
||||
// Adobe's and Narwhal's JS engines will error
|
||||
var useSourceURL = (Function('//@')(), true);
|
||||
} catch(e){ }
|
||||
|
||||
/** Native method shortcuts */
|
||||
var concat = ArrayProto.concat,
|
||||
hasOwnProperty = ObjectProto.hasOwnProperty,
|
||||
push = ArrayProto.push,
|
||||
slice = ArrayProto.slice,
|
||||
toString = ObjectProto.toString;
|
||||
|
||||
/* Native method shortcuts for methods with the same name as other `lodash` methods */
|
||||
var nativeBind = reNative.test(nativeBind = slice.bind) && nativeBind,
|
||||
nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray,
|
||||
nativeIsFinite = window.isFinite,
|
||||
nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys;
|
||||
|
||||
/** Object#toString result shortcuts */
|
||||
var arrayClass = '[object Array]',
|
||||
boolClass = '[object Boolean]',
|
||||
dateClass = '[object Date]',
|
||||
funcClass = '[object Function]',
|
||||
numberClass = '[object Number]',
|
||||
regexpClass = '[object RegExp]',
|
||||
stringClass = '[object String]';
|
||||
|
||||
/** Timer shortcuts */
|
||||
var clearTimeout = window.clearTimeout,
|
||||
setTimeout = window.setTimeout;
|
||||
|
||||
/**
|
||||
* Used to escape characters for inclusion in HTML.
|
||||
* The `>` and `/` characters don't require escaping in HTML and have no
|
||||
@@ -94,39 +144,6 @@
|
||||
'\u2029': 'u2029'
|
||||
};
|
||||
|
||||
/** Object#toString result shortcuts */
|
||||
var arrayClass = '[object Array]',
|
||||
boolClass = '[object Boolean]',
|
||||
dateClass = '[object Date]',
|
||||
funcClass = '[object Function]',
|
||||
numberClass = '[object Number]',
|
||||
regexpClass = '[object RegExp]',
|
||||
stringClass = '[object String]';
|
||||
|
||||
/** Native prototype shortcuts */
|
||||
var ArrayProto = Array.prototype,
|
||||
ObjectProto = Object.prototype;
|
||||
|
||||
/** Native method shortcuts */
|
||||
var concat = ArrayProto.concat,
|
||||
hasOwnProperty = ObjectProto.hasOwnProperty,
|
||||
push = ArrayProto.push,
|
||||
slice = ArrayProto.slice,
|
||||
toString = ObjectProto.toString;
|
||||
|
||||
/* Used if `Function#bind` exists and is inferred to be fast (i.e. all but V8) */
|
||||
var nativeBind = reNative.test(nativeBind = slice.bind) &&
|
||||
/\n|Opera/.test(nativeBind + toString.call(window.opera)) && nativeBind;
|
||||
|
||||
/* Native method shortcuts for methods with the same name as other `lodash` methods */
|
||||
var nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray,
|
||||
nativeIsFinite = window.isFinite,
|
||||
nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys;
|
||||
|
||||
/** Timer shortcuts */
|
||||
var clearTimeout = window.clearTimeout,
|
||||
setTimeout = window.setTimeout;
|
||||
|
||||
/*--------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
@@ -158,8 +175,8 @@
|
||||
}
|
||||
|
||||
/**
|
||||
* By default, Lo-Dash uses ERB-style template delimiters, change the
|
||||
* following template settings to use alternative delimiters.
|
||||
* By default, Lo-Dash uses embedded Ruby (ERB) style template delimiters,
|
||||
* change the following template settings to use alternative delimiters.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
@@ -227,7 +244,7 @@
|
||||
' <% if (objectBranch) { %>\nif (length === length >>> 0) {<% } %>\n' +
|
||||
' <%= arrayBranch.beforeLoop %>;\n' +
|
||||
' while (<%= arrayBranch.loopExp %>) {\n' +
|
||||
' <%= arrayBranch.inLoop %>;\n' +
|
||||
' <%= arrayBranch.inLoop %>\n' +
|
||||
' }' +
|
||||
' <% if (objectBranch) { %>\n}\n<% }' +
|
||||
'}' +
|
||||
@@ -254,7 +271,7 @@
|
||||
// the the `prototype` property of functions regardless of its
|
||||
// [[Enumerable]] value.
|
||||
' if (!(skipProto && index == \'prototype\')<% if (useHas) { %> && <%= hasExp %><% } %>) {\n' +
|
||||
' <%= objectBranch.inLoop %>;\n' +
|
||||
' <%= objectBranch.inLoop %>\n' +
|
||||
' }' +
|
||||
' <% } %>\n' +
|
||||
' }' +
|
||||
@@ -271,7 +288,7 @@
|
||||
' if (shadowed[k] == \'constructor\') {' +
|
||||
' %>!(ctor && ctor.prototype === <%= iteratedObject %>) && <%' +
|
||||
' } %><%= hasExp %>) {\n' +
|
||||
' <%= objectBranch.inLoop %>;\n' +
|
||||
' <%= objectBranch.inLoop %>\n' +
|
||||
' }<%' +
|
||||
' }' +
|
||||
' }' +
|
||||
@@ -340,7 +357,7 @@
|
||||
}
|
||||
};
|
||||
|
||||
/** Reusable iterator options for `invoke`, `map`, `pluck`, and `sortBy` */
|
||||
/** Reusable iterator options for `invoke`, `map`, `pluck`, and `sortBy` */
|
||||
var mapIteratorOptions = {
|
||||
'init': '',
|
||||
'exit': 'if (!collection) return []',
|
||||
@@ -568,7 +585,7 @@
|
||||
*/
|
||||
function tokenizeEscape(match, value) {
|
||||
var index = tokenized.length;
|
||||
tokenized[index] = "'+\n_.escape(" + value + ") +\n'";
|
||||
tokenized[index] = "' +\n__e(" + value + ") +\n'";
|
||||
return token + index;
|
||||
}
|
||||
|
||||
@@ -582,7 +599,7 @@
|
||||
*/
|
||||
function tokenizeInterpolate(match, value) {
|
||||
var index = tokenized.length;
|
||||
tokenized[index] = "'+\n((__t = (" + value + ")) == null ? '' : __t) +\n'";
|
||||
tokenized[index] = "' +\n((__t = (" + value + ")) == null ? '' : __t) +\n'";
|
||||
return token + index;
|
||||
}
|
||||
|
||||
@@ -1859,24 +1876,24 @@
|
||||
*
|
||||
* // basic bind
|
||||
* var func = function(greeting) {
|
||||
* return greeting + ': ' + this.name;
|
||||
* return greeting + ' ' + this.name;
|
||||
* };
|
||||
*
|
||||
* func = _.bind(func, { 'name': 'moe' }, 'hi');
|
||||
* func();
|
||||
* // => 'hi: moe'
|
||||
* // => 'hi moe'
|
||||
*
|
||||
* // lazy bind
|
||||
* var object = {
|
||||
* 'name': 'moe',
|
||||
* 'greet': function(greeting) {
|
||||
* return greeting + ': ' + this.name;
|
||||
* return greeting + ' ' + this.name;
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* var func = _.bind(object, 'greet', 'hi');
|
||||
* func();
|
||||
* // => 'hi: moe'
|
||||
* // => 'hi moe'
|
||||
*
|
||||
* object.greet = function(greeting) {
|
||||
* return greeting + ', ' + this.name + '!';
|
||||
@@ -1894,8 +1911,8 @@
|
||||
methodName = thisArg;
|
||||
thisArg = func;
|
||||
}
|
||||
// use if `Function#bind` is faster
|
||||
else if (nativeBind) {
|
||||
// use if native `Function#bind` is faster
|
||||
else if (useNativeBind || (nativeBind && arguments.length > 2)) {
|
||||
return nativeBind.call.apply(nativeBind, arguments);
|
||||
}
|
||||
|
||||
@@ -1929,7 +1946,6 @@
|
||||
}
|
||||
return func.apply(thisBinding, args);
|
||||
}
|
||||
|
||||
return bound;
|
||||
}
|
||||
|
||||
@@ -3185,7 +3201,8 @@
|
||||
// https://github.com/olado/doT
|
||||
options || (options = {});
|
||||
|
||||
var isEvaluating,
|
||||
var isEscaping,
|
||||
isEvaluating,
|
||||
isInterpolating,
|
||||
result,
|
||||
defaults = lodash.templateSettings,
|
||||
@@ -3207,7 +3224,7 @@
|
||||
|
||||
// tokenize delimiters to avoid escaping them
|
||||
if (escapeDelimiter) {
|
||||
text = text.replace(escapeDelimiter, tokenizeEscape);
|
||||
isEscaping = text != (text = text.replace(escapeDelimiter, tokenizeEscape));
|
||||
}
|
||||
if (interpolateDelimiter) {
|
||||
isInterpolating = text != (text = text.replace(interpolateDelimiter, tokenizeInterpolate));
|
||||
@@ -3225,10 +3242,35 @@
|
||||
// clear stored code snippets
|
||||
tokenized.length = 0;
|
||||
|
||||
// if `options.variable` is not specified, add `data` to the top of the scope chain
|
||||
// strip concating empty strings
|
||||
if (isInterpolating) {
|
||||
text = text.replace(reEmptyStringInterpolate, '__p \+=');
|
||||
}
|
||||
if (isEvaluating) {
|
||||
text = text.replace(reEmptyStringEvaluate, '');
|
||||
if (isInterpolating) {
|
||||
text = text.replace(reEmptyStringHybrid, '__t);');
|
||||
}
|
||||
}
|
||||
|
||||
if (!variable) {
|
||||
variable = defaults.variable;
|
||||
text = 'with (' + variable + ' || {}) {\n' + text + '\n}\n';
|
||||
|
||||
// if `options.variable` is not specified or the template contains "evaluate"
|
||||
// delimiters, add the data object to the top of the scope chain
|
||||
if (isEvaluating || !variable) {
|
||||
text = 'with (' + variable + ' || {}) {\n' + text + '\n}\n';
|
||||
}
|
||||
// else insert data object references to avoid using a with-statement
|
||||
else {
|
||||
if (variable != lastVariable) {
|
||||
lastVariable = variable;
|
||||
reDoubleVariable = RegExp('([(\\s])(' + variable + '\\.' + variable + ')\\b', 'g');
|
||||
}
|
||||
text = text
|
||||
.replace(reInsertVariable, '$&' + variable + '.')
|
||||
.replace(reDoubleVariable, '$1($2 || ' + variable + ')');
|
||||
}
|
||||
}
|
||||
|
||||
text = 'function(' + variable + ') {\n' +
|
||||
@@ -3237,6 +3279,10 @@
|
||||
? ', __t'
|
||||
: ''
|
||||
) +
|
||||
(isEscaping
|
||||
? ', __e = _.escape'
|
||||
: ''
|
||||
) +
|
||||
(isEvaluating
|
||||
? ', __j = Array.prototype.join;\n' +
|
||||
'function print() { __p += __j.call(arguments, \'\') }\n'
|
||||
|
||||
Reference in New Issue
Block a user