Reduce temporary objects created in _.merge, _.clone, and _.isEqual.

Former-commit-id: e6696642505f39eefdf59075ff8a993ab033465a
This commit is contained in:
John-David Dalton
2012-09-10 20:12:42 -07:00
parent 4fc3c969d3
commit 2afb2dd5fd
2 changed files with 42 additions and 33 deletions

View File

@@ -44,7 +44,7 @@
'callee',
'className',
'compareAscending',
'destValue',
'data',
'forIn',
'found',
'funcs',
@@ -66,10 +66,11 @@
'propsLength',
'recursive',
'source',
'stack',
'sources',
'stackLength',
'target',
'valueProp'
'valueProp',
'values'
];
/** Used to minify `compileIterator` option properties */
@@ -107,18 +108,17 @@
'__chain__',
'__proto__',
'__wrapped__',
'a',
'after',
'all',
'amd',
'any',
'attachEvent',
'b',
'bind',
'bindAll',
'chain',
'clearTimeout',
'clone',
'clones',
'collect',
'compact',
'compose',
@@ -214,6 +214,9 @@
'sortBy',
'sortedIndex',
'source',
'sources',
'stackA',
'stackB',
'tail',
'take',
'tap',
@@ -304,7 +307,7 @@
// minify internal properties used by 'compareAscending', `_.clone`, `_.isEqual`, `_.merge`, and `_.sortBy`
(function() {
var properties = ['criteria', 'index', 'source', 'thorough', 'value'],
var properties = ['clones', 'criteria', 'index', 'sources', 'thorough', 'value', 'values'],
snippets = source.match(/( +)(?:function (?:clone|compareAscending|isEqual)|var merge|var sortBy)\b[\s\S]+?\n\1}/g);
if (!snippets) {
@@ -319,7 +322,7 @@
properties.forEach(function(property, index) {
var reBracketProp = RegExp("\\['(" + property + ")'\\]", 'g'),
reDotProp = RegExp('\\.' + property + '\\b', 'g'),
rePropColon = RegExp("(')?\\b" + property + "\\1 *:", 'g');
rePropColon = RegExp("([^?])(')?\\b" + property + "\\2 *:", 'g');
if (isCompilable) {
// add quotes around properties in the inlined `_.merge` and `_.sortBy`
@@ -328,20 +331,20 @@
modified = modified
.replace(reBracketProp, "['" + minNames[index] + "']")
.replace(reDotProp, "['" + minNames[index] + "']")
.replace(rePropColon, "'" + minNames[index] + "':");
.replace(rePropColon, "$1'" + minNames[index] + "':");
}
else {
modified = modified
.replace(reBracketProp, '.' + minNames[index])
.replace(reDotProp, '.' + minNames[index])
.replace(rePropColon, minNames[index] + ':');
.replace(rePropColon, '$1' + minNames[index] + ':');
}
}
else {
modified = modified
.replace(reBracketProp, "['" + minNames[index] + "']")
.replace(reDotProp, '.' + minNames[index])
.replace(rePropColon, "'" + minNames[index] + "':")
.replace(rePropColon, "$1'" + minNames[index] + "':")
// correct `value.source` in regexp branch of `_.clone`
if (property == 'source') {

View File

@@ -1141,13 +1141,14 @@
return ctor(value.source, reFlags.exec(value));
}
var stack = data.stack || (data.stack = []),
length = stack.length;
var clones = data.clones || (data.clones = []),
sources = data.sources || (data.sources = []),
length = clones.length;
// check for circular references and return corresponding clone
while (length--) {
if (stack[length].source == value) {
return stack[length].value;
if (sources[length] == value) {
return clones[length];
}
}
@@ -1155,7 +1156,8 @@
var result = isArr ? ctor(length = value.length) : {};
// add current clone and original source value to the stack of traversed objects
stack.push({ 'value': result, 'source': value });
clones.push(result);
sources.push(value);
// recursively populate clone (susceptible to call stack limits)
if (isArr) {
@@ -1512,12 +1514,13 @@
// assume cyclic structures are equal
// the algorithm for detecting cyclic structures is adapted from ES 5.1
// section 15.12.3, abstract operation `JO` (http://es5.github.com/#x15.12.3)
var stack = data.stack || (data.stack = []),
length = stack.length;
var stackA = data.stackA || (data.stackA = []),
stackB = data.stackB || (data.stackB = []),
length = stackA.length;
while (length--) {
if (stack[length].a == a) {
return stack[length].b == b;
if (stackA[length] == a) {
return stackA[length] == b;
}
}
@@ -1526,7 +1529,8 @@
size = 0;
// add `a` and `b` to the stack of traversed objects
stack.push({ 'a': a, 'b': b });
stackA.push(a);
stackB.push(b);
// recursively compare objects and arrays (susceptible to call stack limits)
if (isArr) {
@@ -1800,7 +1804,7 @@
* @param {Object} [source1, source2, ...] The source objects.
* @param {Object} [indicator] Internally used to indicate that the `stack`
* argument is an array of traversed objects instead of another source object.
* @param {Array} [stack=[]] Internally used to track traversed objects to avoid
* @param {Object} [data={}] Internally used to track traversed objects to avoid
* circular references.
* @returns {Object} Returns the destination object.
* @example
@@ -1821,26 +1825,28 @@
var merge = createIterator(extendIteratorOptions, {
'args': 'object, source, indicator',
'top':
'var isArr, recursive = indicator == isPlainObject, stack = recursive ? arguments[3] : [];\n' +
'var isArr, source, recursive = indicator == isPlainObject,\n' +
' data = recursive ? arguments[3] : { values: [], sources: [] };\n' +
'for (var argsIndex = 1, argsLength = recursive ? 2 : arguments.length; argsIndex < argsLength; argsIndex++) {\n' +
' if (iteratee = arguments[argsIndex]) {',
'inLoop':
'if (value && ((isArr = isArray(value)) || isPlainObject(value))) {\n' +
' var found = false, stackLength = stack.length;\n' +
'if ((source = value) && ((isArr = isArray(source)) || isPlainObject(source))) {\n' +
' var found = false, values = data.values, sources = data.sources, stackLength = sources.length;\n' +
' while (stackLength--) {\n' +
' if (found = stack[stackLength].source == value) break\n' +
' if (found = sources[stackLength] == source) break\n' +
' }\n' +
' if (found) {\n' +
' result[index] = stack[stackLength].value\n' +
' result[index] = values[stackLength]\n' +
' } else {\n' +
' var destValue = (destValue = result[index]) && isArr\n' +
' ? (isArray(destValue) ? destValue : [])\n' +
' : (isPlainObject(destValue) ? destValue : {});\n' +
' stack.push({ value: destValue, source: value });\n' +
' result[index] = callee(destValue, value, isPlainObject, stack)\n' +
' sources.push(source);\n' +
' values.push(value = (value = result[index]) && isArr\n' +
' ? (isArray(value) ? value : [])\n' +
' : (isPlainObject(value) ? value : {})\n' +
' );\n' +
' result[index] = callee(value, source, isPlainObject, data)\n' +
' }\n' +
'} else if (value != null) {\n' +
' result[index] = value\n' +
'} else if (source != null) {\n' +
' result[index] = source\n' +
'}'
});