diff --git a/build/pre-compile.js b/build/pre-compile.js index 843332fe4..0a1a39962 100644 --- a/build/pre-compile.js +++ b/build/pre-compile.js @@ -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') { diff --git a/lodash.js b/lodash.js index db50fead2..114ceefea 100644 --- a/lodash.js +++ b/lodash.js @@ -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' + '}' });