From 10bcb37ca54d02d79ad3b1c0bfc78d92b2bd4c69 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Fri, 29 Jun 2012 19:07:05 -0400 Subject: [PATCH] Inline more functionality into `_.sortBy`. Former-commit-id: 6549e86881b7a93d96854a9ac1b04f0f5a5db0f1 --- build/pre-compile.js | 7 +++- lodash.js | 91 ++++++++++++++++++-------------------------- 2 files changed, 44 insertions(+), 54 deletions(-) diff --git a/build/pre-compile.js b/build/pre-compile.js index e76e1ef02..a8eeba50c 100644 --- a/build/pre-compile.js +++ b/build/pre-compile.js @@ -13,6 +13,7 @@ 'callback', 'className', 'collection', + 'compareAscending', 'ctor', 'funcClass', 'hasOwnProperty', @@ -25,6 +26,7 @@ 'noaccum', 'object', 'objectTypes', + 'prop', 'property', 'result', 'skipProto', @@ -206,6 +208,9 @@ // remove brackets from `_.escape()` in `tokenizeEscape` source = source.replace("_['escape'](\"", '_.escape("'); + // remove brackets from `result[length].value` in `_.sortBy` + source = source.replace("result[length]['value']", 'result[length].value'); + // remove whitespace from string literals source = source.replace(/'(?:(?=(\\?))\1.)*?'/g, function(string) { // avoids removing the '\n' of the `stringEscapes` object @@ -226,7 +231,7 @@ // minify internal properties used by `_.sortBy` (function() { var properties = ['criteria', 'value'], - snippets = source.match(/( +)(?:function compareAscending|function sortBy|var toSortable)\b[\s\S]+?\n\1}/g); + snippets = source.match(/( +)(?:function compareAscending|var sortBy)\b[\s\S]+?\n\1}/g); if (!snippets) { return; diff --git a/lodash.js b/lodash.js index 8ae357369..4af4f17b4 100644 --- a/lodash.js +++ b/lodash.js @@ -286,7 +286,8 @@ /** * Reusable iterator options shared by - * `every`, `filter`, `find`, `forEach`, `forIn`, `forOwn`, `map`, `reject`, and `some`. + * `every`, `filter`, `find`, `forEach`, `forIn`, `forOwn`, `groupBy`, `map`, + * `reject`, `some`, and `sortBy`. */ var baseIteratorOptions = { 'args': 'collection, callback, thisArg', @@ -339,7 +340,7 @@ } }; - /** Reusable iterator options for `invoke`, `map`, and `pluck` */ + /** Reusable iterator options for `invoke`, `map`, `pluck`, and `sortBy` */ var mapIteratorOptions = { 'init': '', 'exit': 'if (!collection) return []', @@ -450,20 +451,20 @@ } // create the function factory var factory = Function( - 'arrayClass, funcClass, hasOwnProperty, identity, iteratorBind, objectTypes, ' + - 'slice, stringClass, toString', + 'arrayClass, compareAscending, funcClass, hasOwnProperty, identity, ' + + 'iteratorBind, objectTypes, slice, stringClass, toString', '"use strict"; return function(' + args + ') {\n' + iteratorTemplate(data) + '\n}' ); // return the compiled function return factory( - arrayClass, funcClass, hasOwnProperty, identity, iteratorBind, objectTypes, - slice, stringClass, toString + arrayClass, compareAscending, funcClass, hasOwnProperty, identity, + iteratorBind, objectTypes, slice, stringClass, toString ); } /** - * Used by `sortBy()` to compare values of the array returned by `toSortable()`, - * sorting them in ascending order. + * Used by `sortBy()` to compare transformed values of `collection`, sorting + * them in ascending order. * * @private * @param {Object} a The object to compare to `b`. @@ -599,35 +600,6 @@ return token + index; } - /** - * Converts `collection` to an array of objects by running each element through - * a transformation `callback`. Each object has a `criteria` property containing - * the transformed value to be sorted and a `value` property containing the - * original unmodified value. The `callback` is invoked with 3 arguments; - * for arrays they are (value, index, array) and for objects they are - * (value, key, object). - * - * @private - * @param {Array|Object} collection The collection to convert. - * @param {Function} callback The function called per iteration. - * @returns {Array} Returns a new array of objects to sort. - */ - var toSortable = createIterator(mapIteratorOptions, { - 'args': 'collection, callback', - 'inLoop': { - 'array': - 'result[index] = {\n' + - ' criteria: callback(collection[index], index, collection),\n' + - ' value: collection[index]\n' + - '}', - 'object': - 'result.push({\n' + - ' criteria: callback(collection[index], index, collection),\n' + - ' value: collection[index]\n' + - '})' - } - }); - /*--------------------------------------------------------------------------*/ /** @@ -1007,7 +979,7 @@ /** - * Produces a new sorted array, ranked in ascending order by the results of + * Produces a new sorted array, sorted in ascending order by the results of * running each element of `collection` through a transformation `callback`. * The `callback` is bound to `thisArg` and invoked with 3 arguments; * for arrays they are (value, index, array) and for objects they are @@ -1033,21 +1005,34 @@ * _.sortBy(['larry', 'brendan', 'moe'], 'length'); * // => ['moe', 'larry', 'brendan'] */ - function sortBy(collection, callback, thisArg) { - if (typeof callback == 'string') { - var prop = callback; - callback = function(collection) { return collection[prop]; }; - } else if (thisArg) { - callback = iteratorBind(callback, thisArg); - } - var result = toSortable(collection, callback).sort(compareAscending), - length = result.length; - - while (length--) { - result[length] = result[length].value; - } - return result; - } + var sortBy = createIterator(baseIteratorOptions, mapIteratorOptions, { + 'top': + 'if (typeof callback == \'string\') {\n' + + ' var prop = callback;\n' + + ' callback = function(collection) { return collection[prop] }\n' + + '}\n' + + 'else if (thisArg) {\n' + + ' callback = iteratorBind(callback, thisArg)\n' + + '}', + 'inLoop': { + 'array': + 'result[index] = {\n' + + ' criteria: callback(collection[index], index, collection),\n' + + ' value: collection[index]\n' + + '}', + 'object': + 'result.push({\n' + + ' criteria: callback(collection[index], index, collection),\n' + + ' value: collection[index]\n' + + '})' + }, + 'bottom': + 'result.sort(compareAscending);\n' + + 'length = result.length;\n' + + 'while (length--) {\n' + + ' result[length] = result[length].value\n' + + '}' + }); /** * Converts the `collection`, into an array. Useful for converting the