diff --git a/README.md b/README.md index 8fd02e0d57..7faccee33d 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,15 @@ -# Lo-Dash v0.2.2 +# Lo-Dash v0.3.0 -A drop-in replacement for Underscore.js, from the devs behind [jsPerf.com](http://jsperf.com), that delivers [performance improvements](http://jsperf.com/lodash-underscore#filterby=family), [bug fixes](https://github.com/bestiejs/lodash#closed-underscorejs-issues), and [additional features](https://github.com/bestiejs/lodash#features). +A drop-in replacement for Underscore.js, from the devs behind [jsPerf.com](http://jsperf.com), that delivers [performance improvements](http://lodash.com/benchmarks), [bug fixes](https://github.com/bestiejs/lodash#closed-underscorejs-issues), and [additional features](https://github.com/bestiejs/lodash#features). Lo-Dash’s performance is gained by avoiding slower native methods, instead opting for simplified non-ES5 compliant methods optimized for common usage, and by leveraging function compilation to reduce the number of overall function calls. +## Download + + * [Development source](https://raw.github.com/bestiejs/lodash/v0.3.0/lodash.js) + * [Production source](https://raw.github.com/bestiejs/lodash/v0.3.0/lodash.min.js) + * For optimal performance, [create a custom build](https://github.com/bestiejs/lodash#custom-builds) with only the features you need + ## Dive in We’ve got [API docs](http://lodash.com/docs), [benchmarks](http://lodash.com/benchmarks), and [unit tests](http://lodash.com/tests). @@ -19,17 +25,21 @@ For more information check out these screencasts over Lo-Dash: ## Features - * AMD loader support + * AMD loader support (RequireJS, curl.js, etc.) * [_.bind](http://lodash.com/docs#bind) supports *"lazy"* binding * [_.debounce](http://lodash.com/docs#debounce)’ed functions match [_.throttle](http://lodash.com/docs#throttle)’ed functions’ return value behavior * [_.forEach](http://lodash.com/docs#forEach) is chainable - * [_.groupBy](http://lodash.com/docs#groupBy) accepts a third, `thisArg`, argument + * [_.forIn](http://lodash.com/docs#forIn) for iterating over an object’s own and inherited properties + * [_.forOwn](http://lodash.com/docs#forOwn) for iterating over an object’s own properties + * [_.groupBy](http://lodash.com/docs#groupBy), [_.sortedIndex](http://lodash.com/docs#sortedIndex), and [_.uniq](http://lodash.com/docs#uniq) accept a `thisArg` argument + * [_.indexOf](http://lodash.com/docs#indexOf) and [_.lastIndexOf](http://lodash.com/docs#lastIndexOf) accept a `fromIndex` argument * [_.partial](http://lodash.com/docs#partial) for more functional fun * [_.size](http://lodash.com/docs#size) supports returning the `length` of string values + * [_.template](http://lodash.com/docs#template) utilizes [sourceURLs](http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl) for easier debugging ## Support -Lo-Dash has been tested in at least Chrome 5-19, Firefox 1.5-12, IE 6-9, Opera 9.25-11.64, Safari 3.0.4-5.1.3, Node.js 0.4.8-0.6.18, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC3. +Lo-Dash has been tested in at least Chrome 5-19, Firefox 1.5-13, IE 6-9, Opera 9.25-11.64, Safari 3.0.4-5.1.3, Node.js 0.4.8-0.6.18, Narwhal 0.3.2, RingoJS 0.8, and Rhino 1.7RC3. ## Custom builds @@ -42,20 +52,28 @@ Mobile builds, with IE bug fixes and method compilation removed, may be created node build mobile ~~~ -Custom builds may be created in two ways: +Custom builds may be created in three ways: - 1. Use the`include` argument to pass the names of the methods to include in the build. + 1. Use the `category` argument to pass the categories of methods to include in the build.
+ Valid categories are *"arrays"*, *"chaining"*, *"collections"*, *"functions"*, *"objects"*, and *"utilities"*. ~~~ bash -node build include=each,filter,map,noConflict -node build include="each, filter, map, noConflict" -node build mobile include=each,filter,map,noConflict +node build category=collections,functions +node build category="collections, functions" +node build mobile category=collections,functions ~~~ - 2. Use the `exclude` argument to pass the names of the methods to exclude from the build. + 2. Use the `include` argument to pass the names of the methods to include in the build. ~~~ bash -node build exclude=isNaN,isUndefined,union,zip -node build exclude="isNaN, isUndefined, union, zip" -node build mobile exclude=isNaN,isUndefined,union,zip +node build include=each,filter,map +node build include="each, filter, map" +node build mobile include=each,filter,map +~~~ + + 3. Use the `exclude` argument to pass the names of the methods to exclude from the build. +~~~ bash +node build exclude=union,uniq,zip +node build exclude="union, uniq, zip" +node build mobile exclude=union,uniq,zip ~~~ Custom builds are saved to `lodash.custom.js` and `lodash.custom.min.js`. @@ -124,17 +142,20 @@ git submodule update --init ## Closed Underscore.js issues - * Ensure `_(...)` returns passed wrapper instances [[test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L95-98)] - * Ensure `_.groupBy` adds values to own, not inherited, properties [[test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L229-236)] - * Ensure `_.throttle` works when called in tight loops [[#502](https://github.com/documentcloud/underscore/issues/502), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L436-446)] - * Fix Firefox, IE, Opera, and Safari object iteration bugs [[#376](https://github.com/documentcloud/underscore/issues/376), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L152-172), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L206-213), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L255-257), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L265-267), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L285-292), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L386-388)] + * Allow iteration of objects with a `length` property [[#148](https://github.com/documentcloud/underscore/issues/148), [#154](https://github.com/documentcloud/underscore/issues/154), [#252](https://github.com/documentcloud/underscore/issues/252), [#448](https://github.com/documentcloud/underscore/issues/448), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L266-272)] + * Ensure array-like objects with invalid `length` properties are treated like regular objects [[test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L237-243), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L533-542), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L661-664)] + * Ensure `_(...)` returns passed wrapper instances [[test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L106-109)] + * Ensure `_.groupBy` adds values to own, not inherited, properties [[test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L317-324)] + * Ensure `_.sortedIndex` supports arrays with high `length` values [[test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L586-595)] + * Ensure `_.throttle` works when called in tight loops [[#502](https://github.com/documentcloud/underscore/issues/502), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L629-639)] + * Fix Firefox, IE, Opera, and Safari object iteration bugs [[#376](https://github.com/documentcloud/underscore/issues/376), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L175-187), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L277-302), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L379-390), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L398-400), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L418-438), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L554-556)] * Handle arrays with `undefined` values correctly in IE < 9 [[#601](https://github.com/documentcloud/underscore/issues/601)] - * Methods should work on pages with incorrectly shimmed native methods [[#7](https://github.com/documentcloud/underscore/issues/7), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L77-83)] - * Register as AMD module, but still export to global [[#431](https://github.com/documentcloud/underscore/pull/431), [test](https://github.com/bestiejs/lodash/blob/32627f45072952df18a64cf5e9f2433d2d32730f/test/test.js#L61-75)] - * `_.forEach` should be chainable [[#142](https://github.com/documentcloud/underscore/issues/142), [test](https://github.com/bestiejs/lodash/blob/5bcd444084c92b1753feeaf66c20323e57a2dac3/test/test.js#L74-77)] - * `_isNaN(new Number(NaN))` should return `true` [[test](https://github.com/bestiejs/lodash/blob/5bcd444084c92b1753feeaf66c20323e57a2dac3/test/test.js#L95-99)] - * `_.reduceRight` should pass correct callback arguments when iterating objects [[test](https://github.com/bestiejs/lodash/blob/5bcd444084c92b1753feeaf66c20323e57a2dac3/test/test.js#L106-116)] - * `_.size` should return the `length` of string values [[test](https://github.com/bestiejs/lodash/blob/5bcd444084c92b1753feeaf66c20323e57a2dac3/test/test.js#L121-127)] + * Methods should work on pages with incorrectly shimmed native methods [[#7](https://github.com/documentcloud/underscore/issues/7), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L88-94)] + * Register as AMD module, but still export to global [[#431](https://github.com/documentcloud/underscore/pull/431), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L72-86)] + * `_.forEach` should be chainable [[#142](https://github.com/documentcloud/underscore/issues/142), [test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L232-235)] + * `_isNaN(new Number(NaN))` should return `true` [[test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L408-410)] + * `_.reduceRight` should pass correct callback arguments when iterating objects [[test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L521-531)] + * `_.size` should return the `length` of string values [[test](https://github.com/bestiejs/lodash/blob/c07e1567a7a12cff2c5ee6cda81306c8bcf126f0/test/test.js#L550-552)] ## Optimized methods (50+) @@ -182,6 +203,7 @@ git submodule update --init * `_.sortedIndex` * `_.template` * `_.throttle` + * `_.times` * `_.toArray` * `_.union` * `_.uniq`, `_.unique` @@ -193,9 +215,21 @@ git submodule update --init ## Changelog +### v0.3.0 + + * Added `category` build option + * Added `fromIndex` argument to `_.indexOf` and `_.lastIndexOf` + * Added `//@ sourceURL` support to `_.template` + * Added `thisArg` argument to `_.sortedIndex` and `_.uniq` + * Added `_.forIn` and `_.forOwn` methods + * Ensured array-like objects with invalid `length` properties are treated like regular objects + * Ensured `_.sortedIndex` supports arrays with high `length` values + * Fixed `prototype` property iteration bug in `_.keys` for Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1 + * Optimized `_.times` and `this` bindings in iterator methods + ### v0.2.2 - * Added mobile build option + * Added `mobile` build option * Ensured `_.find` returns `undefined` for unmatched values * Ensured `_.templateSettings.variable` is compatible with Underscore.js * Optimized `_.escape` @@ -223,7 +257,7 @@ git submodule update --init * Ensured `_(...)` returns passed wrapper instances * Ensured `_.max` and `_.min` support extremely large arrays * Ensured `_.throttle` works in tight loops - * Fixed IE < 9 `[DontEnum]` bug and Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1’s prototype property iteration bug + * Fixed IE < 9 `[DontEnum]` bug and Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1’s `prototype` property iteration bug * Inlined `_.isFunction` calls. * Made `_.debounce`’ed functions match `_.throttle`’ed functions’ return value behavior * Made `_.escape` no longer translate the *">"* character diff --git a/build.js b/build.js index f570f7bdd9..ba7c4fac67 100755 --- a/build.js +++ b/build.js @@ -60,7 +60,7 @@ 'after': [], 'bind': [], 'bindAll': ['bind'], - 'chain': [], + 'chain': ['mixin'], 'clone': ['extend', 'isArray'], 'compact': [], 'compose': [], @@ -72,15 +72,17 @@ 'delay': [], 'difference': ['indexOf'], 'escape': [], - 'every': ['bind', 'createIterator', 'identity'], + 'every': ['createIterator', 'identity'], 'extend': ['createIterator'], - 'filter': ['bind', 'createIterator', 'identity'], - 'find': ['bind', 'createIterator'], + 'filter': ['createIterator', 'identity'], + 'find': ['createIterator'], 'first': [], 'flatten': ['isArray'], - 'forEach': ['bind', 'createIterator'], + 'forEach': ['createIterator'], + 'forIn': ['createIterator'], + 'forOwn': ['createIterator'], 'functions': ['createIterator'], - 'groupBy': ['bind', 'createIterator'], + 'groupBy': ['createIterator'], 'has': [], 'identity': [], 'indexOf': ['sortedIndex'], @@ -106,10 +108,10 @@ 'keys': ['createIterator'], 'last': [], 'lastIndexOf': [], - 'map': ['bind', 'createIterator', 'identity'], - 'max': ['bind'], + 'map': ['createIterator', 'identity'], + 'max': [], 'memoize': [], - 'min': ['bind'], + 'min': [], 'mixin': ['forEach'], 'noConflict': [], 'once': [], @@ -117,23 +119,23 @@ 'pick': [], 'pluck': ['createIterator'], 'range': [], - 'reduce': ['bind', 'createIterator'], - 'reduceRight': ['bind', 'keys'], - 'reject': ['bind', 'createIterator', 'identity'], + 'reduce': ['createIterator'], + 'reduceRight': ['keys'], + 'reject': ['createIterator', 'identity'], 'rest': [], 'result': [], 'shuffle': [], 'size': ['keys'], - 'some': ['bind', 'createIterator', 'identity'], - 'sortBy': ['bind', 'map', 'pluck'], - 'sortedIndex': [], + 'some': ['createIterator', 'identity'], + 'sortBy': ['map', 'pluck'], + 'sortedIndex': ['identity'], 'tap': [], 'template': ['escape'], 'throttle': [], - 'times': ['bind'], + 'times': [], 'toArray': ['values'], 'union': ['indexOf'], - 'uniq': ['indexOf'], + 'uniq': ['identity', 'indexOf'], 'uniqueId': [], 'values': ['createIterator'], 'without': ['indexOf'], @@ -141,18 +143,38 @@ 'zip': ['max', 'pluck'] }; + /** Names of all methods */ + var allMethods = Object.keys(dependencyMap); + /** Names of methods to filter for the build */ - var filterMethods = Object.keys(dependencyMap); + var filterMethods = allMethods; - /** Used to specify if `filterMethods` should be used for exclusion or inclusion */ + /** Used to specify whether `filterMethods` is used for exclusion or inclusion */ var filterType = process.argv.reduce(function(result, value) { - if (!result) { - var pair = value.match(/^(exclude|include)=(.*)$/); - if (pair) { - filterMethods = lodash.intersection(filterMethods, pair[2].split(/, */).map(getRealName)); - return pair[1]; - } + if (result) { + return result; } + var pair = value.match(/^(category|exclude|include)=(.*)$/); + if (!pair) { + return result; + } + + result = pair[1]; + filterMethods = pair[2].split(/, */).map(getRealName); + + if (result == 'category') { + // resolve method names belonging to each category + filterMethods = filterMethods.reduce(function(result, category) { + return result.concat(allMethods.filter(function(funcName) { + return RegExp('@category ' + category + '\\b', 'i').test(matchFunction(source, funcName)); + })); + }, []); + } + else { + // remove nonexistent method names + filterMethods = lodash.intersection(allMethods, filterMethods); + } + return result; }, ''); /*--------------------------------------------------------------------------*/ @@ -251,9 +273,9 @@ // match a function declaration '( +)function ' + funcName + '\\b[\\s\\S]+?\\n\\1}|' + // match a variable declaration with `createIterator` - ' +var ' + funcName + ' *= *(?:[a-zA-Z]+ *\\|\\| *)?createIterator\\((?:{|[a-zA-Z])[\\s\\S]+?\\);|' + + ' +var ' + funcName + ' *=.*?createIterator\\((?:{|[a-zA-Z])[\\s\\S]+?\\);|' + // match a variable declaration with function expression - '( +)var ' + funcName + ' *= *(?:[a-zA-Z]+ *\\|\\| *)?function[\\s\\S]+?\\n\\2};' + + '( +)var ' + funcName + ' *=.*?function[\\s\\S]+?\\n\\2};' + // end non-capturing group ')\\n' )); @@ -293,7 +315,6 @@ if (!snippet) { return source; } - // remove function source = source.replace(matchFunction(source, funcName), ''); @@ -350,7 +371,7 @@ * @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 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; }); } @@ -359,25 +380,26 @@ // custom build (function() { - // exit early if "exclude" or "include" options aren't specified + // exit early if "category", "exclude", or "include" options aren't specified if (!filterType) { return; } - // remove the specified functions and their dependants if (filterType == 'exclude') { + // remove methods that are named in `filterMethods` and their dependants filterMethods.forEach(function(funcName) { getDependants(funcName).concat(funcName).forEach(function(otherName) { source = removeFunction(source, otherName); }); }); } - // else remove all but the specified functions and their dependencies else { + // add dependencies to `filterMethods` filterMethods = lodash.uniq(filterMethods.reduce(function(result, funcName) { result.push.apply(result, getDependencies(funcName).concat(funcName)); return result; }, [])); + // remove methods that aren't named in `filterMethods` lodash.each(dependencyMap, function(dependencies, otherName) { if (filterMethods.indexOf(otherName) < 0) { source = removeFunction(source, otherName); @@ -439,25 +461,20 @@ if (isMobile) { // inline functions defined with `createIterator` lodash.functions(lodash).forEach(function(funcName) { - var reFunc = RegExp('( +var ' + funcName + ' *= *)((?:[a-zA-Z]+ *\\|\\| *)?)createIterator\\(((?:{|[a-zA-Z])[\\s\\S]+?)\\);\\n'), - parts = source.match(reFunc); + // match `funcName` with pseudo private `_` prefixes removed to allow matching `shimKeys` + var reFunc = RegExp('(\\bvar ' + funcName.replace(/^_/, '') + ' *= *)createIterator\\(((?:{|[a-zA-Z])[\\s\\S]+?)\\);\\n'); // skip if not defined with `createIterator` - if (!parts) { + if (!reFunc.test(source)) { return; } - // extract function's code - var code = funcName == 'keys' - ? '$1$2' + lodash._createIterator(Function('return ' + parts[3])()) - : '$1' + lodash[funcName]; - - // format code - code = code.replace(/\n(?:.*)/g, function(match) { + // extract and format the function's code + var code = (lodash[funcName] + '').replace(/\n(?:.*)/g, function(match) { match = match.slice(1); return (match == '}' ? '\n ' : '\n ') + match; - }) + ';\n'; + }); - source = source.replace(reFunc, code); + source = source.replace(reFunc, '$1' + code + ';\n'); }); // remove `iteratorTemplate` @@ -490,7 +507,7 @@ } // remove pseudo private properties - source = source.replace(/(?:\s*\/\/.*)*\s*lodash\._(?:createIterator|iteratorTemplate)\b.+\n/g, '\n'); + source = source.replace(/(?:(?:\s*\/\/.*)*\s*lodash\._[^=]+=.+\n)+/g, '\n'); /*--------------------------------------------------------------------------*/ diff --git a/build/pre-compile.js b/build/pre-compile.js index 7270bebc06..18c34b43c6 100644 --- a/build/pre-compile.js +++ b/build/pre-compile.js @@ -9,7 +9,6 @@ var compiledVars = [ 'accumulator', 'arrayClass', - 'bind', 'callback', 'className', 'collection', @@ -19,6 +18,7 @@ 'hasOwnProperty', 'identity', 'index', + 'iteratorBind', 'length', 'object', 'objectTypes', @@ -101,6 +101,8 @@ 'foldl', 'foldr', 'forEach', + 'forIn', + 'forOwn', 'functions', 'groupBy', 'has', @@ -193,21 +195,30 @@ // remove copyright to add later in post-compile.js source = source.replace(/\/\*![\s\S]+?\*\//, ''); - // correct JSDoc tags for Closure Compiler + // remove unrecognized JSDoc tags so Closure Compiler won't complain source = source.replace(/@(?:alias|category)\b.*/g, ''); // add brackets to whitelisted properties so Closure Compiler won't mung them // http://code.google.com/closure/compiler/docs/api-tutorial3.html#export source = source.replace(RegExp('\\.(' + propWhitelist.join('|') + ')\\b', 'g'), "['$1']"); + // remove brackets from `_.escape(__t)` in `tokenizeEscape` + source = source.replace("_['escape'](__t)", '_.escape(__t)'); + // remove whitespace from string literals source = source.replace(/'(?:(?=(\\?))\1.)*?'/g, function(string) { - // avoids removing the '\n' of the `escapes` object - return string.replace(/\[object |else if|function | in |return\s+[\w']|throw |typeof |use strict|var |'\\n'|\\\\n|\\n|\s+/g, function(match) { + // avoids removing the '\n' of the `stringEscapes` object + return string.replace(/\[object |else if|function | in |return\s+[\w']|throw |typeof |use strict|var |@ |'\\n'|\\\\n|\\n|\s+/g, function(match) { return match == false || match == '\\n' ? '' : match; }); }); + // remove newline from double-quoted string in `_.template` + source = source.replace('"\';\\n"', '"\';"'); + + // remove debug sourceURL in `_.template` + source = source.replace(/\+(?:\s*\/\/.*)*\s*'\/\/@ sourceURL=[^;]+/, ''); + // minify `_.sortBy` internal properties (function() { var properties = ['criteria', 'value'], @@ -276,7 +287,7 @@ // correct external boolean literals else if (variable == 'true' || variable == 'false') { result = result - .replace(RegExp(': *' + minNames[index] + ',', 'g'), ':' + variable + ',') + .replace(RegExp(': *' + minNames[index] + '([,\\n])', 'g'), ':' + variable + '$1') .replace(RegExp('\\b' + minNames[index] + ';', 'g'), variable + ';'); } }); diff --git a/doc/README.md b/doc/README.md index ad24053066..60f405c612 100644 --- a/doc/README.md +++ b/doc/README.md @@ -1,4 +1,4 @@ -# Lo-Dash v0.2.2 +# Lo-Dash v0.3.0 @@ -9,7 +9,7 @@ * [`_`](#_value) * [`_.VERSION`](#_version) * [`_.after`](#_aftern-func) -* [`_.bind`](#_bindfunc--arg1-arg2-) +* [`_.bind`](#_bindfunc--thisarg-arg1-arg2-) * [`_.bindAll`](#_bindallobject--methodname1-methodname2-) * [`_.chain`](#_chainvalue) * [`_.clone`](#_clonevalue) @@ -22,18 +22,20 @@ * [`_.delay`](#_delayfunc-wait--arg1-arg2-) * [`_.difference`](#_differencearray--array1-array2-) * [`_.escape`](#_escapestring) -* [`_.every`](#_everycollection-callback--thisarg) +* [`_.every`](#_everycollection--callbackidentity-thisarg) * [`_.extend`](#_extendobject--source1-source2-) -* [`_.filter`](#_filtercollection-callback--thisarg) +* [`_.filter`](#_filtercollection--callbackidentity-thisarg) * [`_.find`](#_findcollection-callback--thisarg) * [`_.first`](#_firstarray--n-guard) * [`_.flatten`](#_flattenarray-shallow) * [`_.forEach`](#_foreachcollection-callback--thisarg) +* [`_.forIn`](#_forinobject-callback--thisarg) +* [`_.forOwn`](#_forownobject-callback--thisarg) * [`_.functions`](#_functionsobject) * [`_.groupBy`](#_groupbyarray-callback--thisarg) * [`_.has`](#_hasobject-property) * [`_.identity`](#_identityvalue) -* [`_.indexOf`](#_indexofarray-value--issortedfalse) +* [`_.indexOf`](#_indexofarray-value--fromindex0) * [`_.initial`](#_initialarray--n-guard) * [`_.intersection`](#_intersectionarray1-array2-) * [`_.invoke`](#_invokearray-methodname--arg1-arg2-) @@ -55,8 +57,8 @@ * [`_.isUndefined`](#_isundefinedvalue) * [`_.keys`](#_keysobject) * [`_.last`](#_lastarray--n-guard) -* [`_.lastIndexOf`](#_lastindexofarray-value) -* [`_.map`](#_mapcollection-callback--thisarg) +* [`_.lastIndexOf`](#_lastindexofarray-value--fromindexarraylength-1) +* [`_.map`](#_mapcollection--callbackidentity-thisarg) * [`_.max`](#_maxarray--callback-thisarg) * [`_.memoize`](#_memoizefunc--resolver) * [`_.min`](#_minarray--callback-thisarg) @@ -69,21 +71,21 @@ * [`_.range`](#_rangestart0-end--step1) * [`_.reduce`](#_reducecollection-callback--accumulator-thisarg) * [`_.reduceRight`](#_reducerightcollection-callback--accumulator-thisarg) -* [`_.reject`](#_rejectcollection-callback--thisarg) +* [`_.reject`](#_rejectcollection--callbackidentity-thisarg) * [`_.rest`](#_restarray--n-guard) * [`_.result`](#_resultobject-property) * [`_.shuffle`](#_shufflearray) * [`_.size`](#_sizevalue) -* [`_.some`](#_somecollection-callback--thisarg) +* [`_.some`](#_somecollection--callbackidentity-thisarg) * [`_.sortBy`](#_sortbyarray-callback--thisarg) -* [`_.sortedIndex`](#_sortedindexarray-value--callback) +* [`_.sortedIndex`](#_sortedindexarray-value--callbackidentity-thisarg) * [`_.tap`](#_tapvalue-interceptor) * [`_.template`](#_templatetext-data-options) * [`_.throttle`](#_throttlefunc-wait) * [`_.times`](#_timesn-callback--thisarg) * [`_.toArray`](#_toarraycollection) * [`_.union`](#_unionarray1-array2-) -* [`_.uniq`](#_uniqarray--issortedfalse-callback) +* [`_.uniq`](#_uniqarray--issortedfalse-callbackidentity-thisarg) * [`_.uniqueId`](#_uniqueidprefix) * [`_.values`](#_valuescollection) * [`_.without`](#_withoutarray--value1-value2-) @@ -127,7 +129,7 @@ ### `_(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L115 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L134 "View in source") [Ⓣ][1] The `lodash` function. @@ -145,7 +147,7 @@ The `lodash` function. ### `_.VERSION` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3092 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L3271 "View in source") [Ⓣ][1] *(String)*: The semantic version number. @@ -157,7 +159,7 @@ The `lodash` function. ### `_.after(n, func)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1622 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1740 "View in source") [Ⓣ][1] Creates a new function that is restricted to executing only after it is called `n` times. @@ -174,7 +176,7 @@ var renderNotes = _.after(notes.length, render); _.forEach(notes, function(note) { note.asyncSave({ 'success': renderNotes }); }); -// renderNotes is run once, after all notes have saved. +// `renderNotes` is run once, after all notes have saved ~~~ * * * @@ -184,14 +186,15 @@ _.forEach(notes, function(note) { -### `_.bind(func [, arg1, arg2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1673 "View in source") [Ⓣ][1] +### `_.bind(func [, thisArg, arg1, arg2, ...])` +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1794 "View in source") [Ⓣ][1] Creates a new function that, when called, invokes `func` with the `this` binding of `thisArg` and prepends any additional `bind` arguments to those passed to the bound function. Lazy defined methods may be bound by passing the object they are bound to as `func` and the method name as `thisArg`. #### Arguments 1. `func` *(Function|Object)*: The function to bind or the object the method belongs to. -2. `[arg1, arg2, ...]` *(Mixed)*: Arguments to be partially applied. +2. `[thisArg]` *(Mixed)*: The `this` binding of `func` or the method name. +3. `[arg1, arg2, ...]` *(Mixed)*: Arguments to be partially applied. #### Returns *(Function)*: Returns the new bound function. @@ -199,7 +202,10 @@ Creates a new function that, when called, invokes `func` with the `this` binding #### Example ~~~ js // basic bind -var func = function(greeting) { return greeting + ': ' + this.name; }; +var func = function(greeting) { + return greeting + ': ' + this.name; +}; + func = _.bind(func, { 'name': 'moe' }, 'hi'); func(); // => 'hi: moe' @@ -217,11 +223,11 @@ func(); // => 'hi: moe' object.greet = function(greeting) { - return greeting + ' ' + this.name + '!'; + return greeting + ', ' + this.name + '!'; }; func(); -// => 'hi moe!' +// => 'hi, moe!' ~~~ * * * @@ -232,9 +238,9 @@ func(); ### `_.bindAll(object [, methodName1, methodName2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1744 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1865 "View in source") [Ⓣ][1] -Binds methods on the `object` to the object, overwriting the non-bound method. If no method names are provided, all the function properties of the `object` will be bound. +Binds methods on `object` to `object`, overwriting the existing method. If no method names are provided, all the function properties of `object` will be bound. #### Arguments 1. `object` *(Object)*: The object to bind and assign the bound methods to. @@ -264,7 +270,7 @@ jQuery('#lodash_button').on('click', buttonView.onClick); ### `_.chain(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L3044 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L3223 "View in source") [Ⓣ][1] Wraps the value in a `lodash` chainable object. @@ -298,7 +304,7 @@ var youngest = _.chain(stooges) ### `_.clone(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2070 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2191 "View in source") [Ⓣ][1] Create a shallow clone of the `value`. Any nested objects or arrays will be assigned by reference and not cloned. @@ -322,7 +328,7 @@ _.clone({ 'name': 'moe' }); ### `_.compact(array)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L883 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L945 "View in source") [Ⓣ][1] Produces a new array with all falsey values of `array` removed. The values `false`, `null`, `0`, `""`, `undefined` and `NaN` are all falsey. @@ -346,7 +352,7 @@ _.compact([0, 1, false, 2, '', 3]); ### `_.compose([func1, func2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1776 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1897 "View in source") [Ⓣ][1] Creates a new function that is the composition of the passed functions, where each function consumes the return value of the function that follows. In math terms, composing thefunctions `f()`, `g()`, and `h()` produces `f(g(h()))`. @@ -373,7 +379,7 @@ welcome('moe'); ### `_.contains(collection, target)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L525 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L592 "View in source") [Ⓣ][1] Checks if a given `target` value is present in a `collection` using strict equality for comparisons, i.e. `===`. @@ -398,7 +404,7 @@ _.contains([1, 2, 3], 3); ### `_.debounce(func, wait, immediate)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1809 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1930 "View in source") [Ⓣ][1] Creates a new function that will delay the execution of `func` until after `wait` milliseconds have elapsed since the last time it was invoked. Pass `true` for `immediate` to cause debounce to invoke `func` on the leading, instead of the trailing, edge of the `wait` timeout. Subsequent calls to the debounced function will return the result of the last `func` call. @@ -424,7 +430,7 @@ jQuery(window).on('resize', lazyLayout); ### `_.defaults(object [, defaults1, defaults2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2093 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2214 "View in source") [Ⓣ][1] Assigns missing properties in `object` with default values from the defaults objects. As soon as a property is set, additional defaults of the same property will be ignored. @@ -438,8 +444,8 @@ Assigns missing properties in `object` with default values from the defaults obj #### Example ~~~ js var iceCream = { 'flavor': 'chocolate' }; -_.defaults(iceCream, { 'flavor': 'vanilla', 'sprinkles': 'lots' }); -// => { 'flavor': 'chocolate', 'sprinkles': 'lots' } +_.defaults(iceCream, { 'flavor': 'vanilla', 'sprinkles': 'rainbow' }); +// => { 'flavor': 'chocolate', 'sprinkles': 'rainbow' } ~~~ * * * @@ -450,7 +456,7 @@ _.defaults(iceCream, { 'flavor': 'vanilla', 'sprinkles': 'lots' }); ### `_.defer(func [, arg1, arg2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1874 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1995 "View in source") [Ⓣ][1] Defers executing the `func` function until the current call stack has cleared. Additional arguments are passed to `func` when it is invoked. @@ -464,7 +470,7 @@ Defers executing the `func` function until the current call stack has cleared. A #### Example ~~~ js _.defer(function() { alert('deferred'); }); -// Returns from the function before the alert runs. +// returns from the function before `alert` is called ~~~ * * * @@ -475,7 +481,7 @@ _.defer(function() { alert('deferred'); }); ### `_.delay(func, wait [, arg1, arg2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1854 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1975 "View in source") [Ⓣ][1] Executes the `func` function after `wait` milliseconds. Additional arguments are passed to `func` when it is invoked. @@ -502,7 +508,7 @@ _.delay(log, 1000, 'logged later'); ### `_.difference(array [, array1, array2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L912 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L974 "View in source") [Ⓣ][1] Produces a new array of `array` values not present in the other arrays using strict equality for comparisons, i.e. `===`. @@ -527,9 +533,9 @@ _.difference([1, 2, 3, 4, 5], [5, 2, 10]); ### `_.escape(string)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2741 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2914 "View in source") [Ⓣ][1] -Escapes a string for insertion into HTML, replacing `&`, `<`, `"`, `'`, and `/` characters. +Escapes a string for inclusion in HTML, replacing `&`, `<`, `"`, and `'` characters. #### Arguments 1. `string` *(String)*: The string to escape. @@ -550,14 +556,14 @@ _.escape('Curly, Larry & Moe'); -### `_.every(collection, callback [, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L549 "View in source") [Ⓣ][1] +### `_.every(collection [, callback=identity, thisArg])` +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L617 "View in source") [Ⓣ][1] -Checks if the `callback` returns a truthy value for **all** elements of a `collection`. The `callback` is invoked with `3` arguments; for arrays they are *(value, index, array)* and for objects they are *(value, key, object)*. +Checks if the `callback` returns a truthy value for **all** elements of a `collection`. The `callback` is bound to `thisArg` and invoked with `3` arguments; for arrays they are *(value, index, array)* and for objects they are *(value, key, object)*. #### Arguments 1. `collection` *(Array|Object)*: The collection to iterate over. -2. `callback` *(Function)*: The function called per iteration. +2. `[callback=identity]` *(Function)*: The function called per iteration. 3. `[thisArg]` *(Mixed)*: The `this` binding for the callback. #### Returns @@ -577,7 +583,7 @@ _.every([true, 1, null, 'yes'], Boolean); ### `_.extend(object [, source1, source2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2112 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2233 "View in source") [Ⓣ][1] Copies enumerable properties from the source objects to the `destination` object. Subsequent sources will overwrite propery assignments of previous sources. @@ -601,14 +607,14 @@ _.extend({ 'name': 'moe' }, { 'age': 40 }); -### `_.filter(collection, callback [, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L570 "View in source") [Ⓣ][1] +### `_.filter(collection [, callback=identity, thisArg])` +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L638 "View in source") [Ⓣ][1] -Examines each value in a `collection`, returning an array of all values the `callback` returns truthy for. The `callback` is invoked with `3` arguments; for arrays they are *(value, index, array)* and for objects they are *(value, key, object)*. +Examines each value in a `collection`, returning an array of all values the `callback` returns truthy for. The `callback` is bound to `thisArg` and invoked with `3` arguments; for arrays they are *(value, index, array)* and for objects they are *(value, key, object)*. #### Arguments 1. `collection` *(Array|Object)*: The collection to iterate over. -2. `callback` *(Function)*: The function called per iteration. +2. `[callback=identity]` *(Function)*: The function called per iteration. 3. `[thisArg]` *(Mixed)*: The `this` binding for the callback. #### Returns @@ -628,9 +634,9 @@ var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }) ### `_.find(collection, callback [, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L592 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L660 "View in source") [Ⓣ][1] -Examines each value in a `collection`, returning the first one the `callback` returns truthy for. The function returns as soon as it finds an acceptable value, and does not iterate over the entire `collection`. The `callback` is invoked with `3` arguments; for arrays they are *(value, index, array)* and for objects they are *(value, key, object)*. +Examines each value in a `collection`, returning the first one the `callback` returns truthy for. The function returns as soon as it finds an acceptable value, and does not iterate over the entire `collection`. The `callback` is bound to `thisArg` and invoked with `3` arguments; for arrays they are *(value, index, array)* and for objects they are *(value, key, object)*. #### Arguments 1. `collection` *(Array|Object)*: The collection to iterate over. @@ -654,7 +660,7 @@ var even = _.find([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); ### `_.first(array [, n, guard])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L945 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1007 "View in source") [Ⓣ][1] Gets the first value of the `array`. Pass `n` to return the first `n` values of the `array`. @@ -680,7 +686,7 @@ _.first([5, 4, 3, 2, 1]); ### `_.flatten(array, shallow)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L967 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1029 "View in source") [Ⓣ][1] Flattens a nested array *(the nesting can be to any depth)*. If `shallow` is truthy, `array` will only be flattened a single level. @@ -708,9 +714,9 @@ _.flatten([1, [2], [3, [[4]]]], true); ### `_.forEach(collection, callback [, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L619 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L687 "View in source") [Ⓣ][1] -Iterates over a `collection`, executing the `callback` for each value in the `collection`. The `callback` is bound to the `thisArg` value, if one is passed. The `callback` is invoked with `3` arguments; for arrays they are *(value, index, array)* and for objects they are *(value, key, object)*. +Iterates over a `collection`, executing the `callback` for each value in the `collection`. The `callback` is bound to `thisArg` and invoked with `3` arguments; for arrays they are *(value, index, array)* and for objects they are *(value, key, object)*. #### Arguments 1. `collection` *(Array|Object)*: The collection to iterate over. @@ -722,11 +728,75 @@ Iterates over a `collection`, executing the `callback` for each value in the `co #### Example ~~~ js -_.forEach({ 'one': 1, 'two': 2, 'three': 3}, function(num) { alert(num); }); -// => alerts each number in turn +_([1, 2, 3]).forEach(alert).join(','); +// => alerts each number and returns '1,2,3' -_([1, 2, 3]).forEach(function(num) { alert(num); }).join(','); -// => alerts each number in turn and returns '1,2,3' +_.forEach({ 'one': 1, 'two': 2, 'three': 3 }, alert); +// => alerts each number (order is not guaranteed) +~~~ + +* * * + + + + + + +### `_.forIn(object, callback [, thisArg])` +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2262 "View in source") [Ⓣ][1] + +Iterates over an `object`'s enumerable own and inherited properties, executing the `callback` for each property. The `callback` is bound to `thisArg` and invoked with `3` arguments; *(value, key, object)*. + +#### Arguments +1. `object` *(Object)*: The object to iterate over. +2. `callback` *(Function)*: The function called per iteration. +3. `[thisArg]` *(Mixed)*: The `this` binding for the callback. + +#### Returns +*(Object)*: Returns the `object`. + +#### Example +~~~ js +function Dog(name) { + this.name = name; +} + +Dog.prototype.bark = function() { + alert('Woof, woof!'); +}; + +_.forIn(new Dog('Dagny'), function(value, key) { + alert(key); +}); +// => alerts 'name' and 'bark' (order is not guaranteed) +~~~ + +* * * + + + + + + +### `_.forOwn(object, callback [, thisArg])` +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2285 "View in source") [Ⓣ][1] + +Iterates over an `object`'s enumerable own properties, executing the `callback` for each property. The `callback` is bound to `thisArg` and invoked with `3` arguments; *(value, key, object)*. + +#### Arguments +1. `object` *(Object)*: The object to iterate over. +2. `callback` *(Function)*: The function called per iteration. +3. `[thisArg]` *(Mixed)*: The `this` binding for the callback. + +#### Returns +*(Object)*: Returns the `object`. + +#### Example +~~~ js +_.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) { + alert(key); +}); +// => alerts '0', '1', and 'length' (order is not guaranteed) ~~~ * * * @@ -737,7 +807,7 @@ _([1, 2, 3]).forEach(function(num) { alert(num); }).join(','); ### `_.functions(object)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2129 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2302 "View in source") [Ⓣ][1] Produces a sorted array of the properties, own and inherited, of `object` that have function values. @@ -761,9 +831,9 @@ _.functions(_); ### `_.groupBy(array, callback [, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1009 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1071 "View in source") [Ⓣ][1] -Splits a `collection` into sets, grouped by the result of running each value through `callback`. The `callback` is invoked with `3` arguments; *(value, index, array)*. The `callback` argument may also be the name of a property to group by. +Splits `array` into sets, grouped by the result of running each value through `callback`. The `callback` is bound to `thisArg` and invoked with `3` arguments; *(value, index, array)*. The `callback` argument may also be the name of a property to group by. #### Arguments 1. `array` *(Array)*: The array to iterate over. @@ -793,7 +863,7 @@ _.groupBy(['one', 'two', 'three'], 'length'); ### `_.has(object, property)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2152 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2325 "View in source") [Ⓣ][1] Checks if the specified object `property` exists and is a direct property, instead of an inherited property. @@ -818,7 +888,7 @@ _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b'); ### `_.identity(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2767 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2933 "View in source") [Ⓣ][1] This function returns the first argument passed to it. Note: It is used throughout Lo-Dash as a default callback. @@ -842,23 +912,29 @@ moe === _.identity(moe); -### `_.indexOf(array, value [, isSorted=false])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1094 "View in source") [Ⓣ][1] +### `_.indexOf(array, value [, fromIndex=0])` +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1165 "View in source") [Ⓣ][1] Gets the index at which the first occurrence of `value` is found using strict equality for comparisons, i.e. `===`. If the `array` is already sorted, passing `true` for `isSorted` will run a faster binary search. #### Arguments 1. `array` *(Array)*: The array to search. 2. `value` *(Mixed)*: The value to search for. -3. `[isSorted=false]` *(Boolean)*: A flag to indicate that the `array` is already sorted. +3. `[fromIndex=0]` *(Boolean|Number)*: The index to start searching from or `true` to perform a binary search on a sorted `array`. #### Returns *(Number)*: Returns the index of the matched value or `-1`. #### Example ~~~ js -_.indexOf([1, 2, 3], 2); +_.indexOf([1, 2, 3, 1, 2, 3], 2); // => 1 + +_.indexOf([1, 2, 3, 1, 2, 3], 2, 3); +// => 4 + +_.indexOf([1, 1, 2, 2, 3, 3], 2, true); +// => 2 ~~~ * * * @@ -869,7 +945,7 @@ _.indexOf([1, 2, 3], 2); ### `_.initial(array [, n, guard])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1128 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1202 "View in source") [Ⓣ][1] Gets all but the last value of the `array`. Pass `n` to exclude the last `n` values from the result. @@ -883,8 +959,8 @@ Gets all but the last value of the `array`. Pass `n` to exclude the last `n` val #### Example ~~~ js -_.initial([5, 4, 3, 2, 1]); -// => [5, 4, 3, 2] +_.initial([3, 2, 1]); +// => [3, 2] ~~~ * * * @@ -895,7 +971,7 @@ _.initial([5, 4, 3, 2, 1]); ### `_.intersection([array1, array2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1146 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1220 "View in source") [Ⓣ][1] Computes the intersection of all the passed-in arrays. @@ -919,13 +995,13 @@ _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]); ### `_.invoke(array, methodName [, arg1, arg2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1179 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1256 "View in source") [Ⓣ][1] -Calls the method named by `methodName` for each value of the `collection`. Additional arguments will be passed to each invoked method. +Invokes the method named by `methodName` on each element of `array`. Additional arguments will be passed to each invoked method. If `methodName` is a function it will be invoked for, and `this` bound to, each element of `array`. #### Arguments 1. `array` *(Array)*: The array to iterate over. -2. `methodName` *(String)*: The name of the method to invoke. +2. `methodName` *(Function|String)*: The name of the method to invoke or the function invoked per iteration. 3. `[arg1, arg2, ...]` *(Mixed)*: Arguments to invoke the method with. #### Returns @@ -945,7 +1021,7 @@ _.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); ### `_.isArguments(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2172 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2345 "View in source") [Ⓣ][1] Checks if a `value` is an `arguments` object. @@ -972,7 +1048,7 @@ _.isArguments([1, 2, 3]); ### `_.isArray(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2198 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2371 "View in source") [Ⓣ][1] Checks if a `value` is an array. @@ -999,7 +1075,7 @@ _.isArray([1, 2, 3]); ### `_.isBoolean(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2215 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2388 "View in source") [Ⓣ][1] Checks if a `value` is a boolean *(`true` or `false`)* value. @@ -1023,7 +1099,7 @@ _.isBoolean(null); ### `_.isDate(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2232 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2405 "View in source") [Ⓣ][1] Checks if a `value` is a date. @@ -1047,7 +1123,7 @@ _.isDate(new Date); ### `_.isElement(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2249 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2422 "View in source") [Ⓣ][1] Checks if a `value` is a DOM element. @@ -1071,7 +1147,7 @@ _.isElement(document.body); ### `_.isEmpty(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2270 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2443 "View in source") [Ⓣ][1] Checks if a `value` is empty. Arrays or strings with a length of `0` and objects with no enumerable own properties are considered "empty". @@ -1098,7 +1174,7 @@ _.isEmpty({}); ### `_.isEqual(a, b [, stack])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2304 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2477 "View in source") [Ⓣ][1] Performs a deep comparison between two values to determine if they are equivalent to each other. @@ -1130,7 +1206,7 @@ _.isEqual(moe, clone); ### `_.isFinite(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2456 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2629 "View in source") [Ⓣ][1] Checks if a `value` is a finite number. @@ -1160,7 +1236,7 @@ _.isFinite(Infinity); ### `_.isFunction(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2473 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2646 "View in source") [Ⓣ][1] Checks if a `value` is a function. @@ -1184,9 +1260,9 @@ _.isFunction(''.concat); ### `_.isNaN(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2524 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2697 "View in source") [Ⓣ][1] -Checks if a `value` is `NaN`. Note: this is not the same as native `isNaN`, which will return true for `undefined` and other values. See http://es5.github.com/#x15.1.2.4. +Checks if a `value` is `NaN`. Note: This is not the same as native `isNaN`, which will return true for `undefined` and other values. See http://es5.github.com/#x15.1.2.4. #### Arguments 1. `value` *(Mixed)*: The value to check. @@ -1217,7 +1293,7 @@ _.isNaN(undefined); ### `_.isNull(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2546 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2719 "View in source") [Ⓣ][1] Checks if a `value` is `null`. @@ -1244,7 +1320,7 @@ _.isNull(undefined); ### `_.isNumber(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2563 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2736 "View in source") [Ⓣ][1] Checks if a `value` is a number. @@ -1268,7 +1344,7 @@ _.isNumber(8.4 * 5; ### `_.isObject(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2494 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2667 "View in source") [Ⓣ][1] Checks if a `value` is the language type of Object. *(e.g. arrays, functions, objects, regexps, `new Number(0)*`, and `new String('')`) @@ -1295,7 +1371,7 @@ _.isObject(1); ### `_.isRegExp(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2580 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2753 "View in source") [Ⓣ][1] Checks if a `value` is a regular expression. @@ -1319,7 +1395,7 @@ _.isRegExp(/moe/); ### `_.isString(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2597 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2770 "View in source") [Ⓣ][1] Checks if a `value` is a string. @@ -1343,7 +1419,7 @@ _.isString('moe'); ### `_.isUndefined(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2614 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2787 "View in source") [Ⓣ][1] Checks if a `value` is `undefined`. @@ -1367,7 +1443,7 @@ _.isUndefined(void 0); ### `_.keys(object)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2631 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2804 "View in source") [Ⓣ][1] Produces an array of the `object`'s enumerable own property names. @@ -1380,7 +1456,7 @@ Produces an array of the `object`'s enumerable own property names. #### Example ~~~ js _.keys({ 'one': 1, 'two': 2, 'three': 3 }); -// => ['one', 'two', 'three'] +// => ['one', 'two', 'three'] (order is not guaranteed) ~~~ * * * @@ -1391,7 +1467,7 @@ _.keys({ 'one': 1, 'two': 2, 'three': 3 }); ### `_.last(array [, n, guard])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1209 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1286 "View in source") [Ⓣ][1] Gets the last value of the `array`. Pass `n` to return the lasy `n` values of the `array`. @@ -1405,7 +1481,7 @@ Gets the last value of the `array`. Pass `n` to return the lasy `n` values of th #### Example ~~~ js -_.last([5, 4, 3, 2, 1]); +_.last([3, 2, 1]); // => 1 ~~~ @@ -1416,14 +1492,15 @@ _.last([5, 4, 3, 2, 1]); -### `_.lastIndexOf(array, value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1229 "View in source") [Ⓣ][1] +### `_.lastIndexOf(array, value [, fromIndex=array.length-1])` +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1310 "View in source") [Ⓣ][1] Gets the index at which the last occurrence of `value` is found using strict equality for comparisons, i.e. `===`. #### Arguments 1. `array` *(Array)*: The array to search. 2. `value` *(Mixed)*: The value to search for. +3. `[fromIndex=array.length-1]` *(Number)*: The index to start searching from. #### Returns *(Number)*: Returns the index of the matched value or `-1`. @@ -1432,6 +1509,9 @@ Gets the index at which the last occurrence of `value` is found using strict equ ~~~ js _.lastIndexOf([1, 2, 3, 1, 2, 3], 2); // => 4 + +_.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3); +// => 1 ~~~ * * * @@ -1441,14 +1521,14 @@ _.lastIndexOf([1, 2, 3, 1, 2, 3], 2); -### `_.map(collection, callback [, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L643 "View in source") [Ⓣ][1] +### `_.map(collection [, callback=identity, thisArg])` +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L711 "View in source") [Ⓣ][1] -Produces a new array of values by mapping each value in the `collection` through a transformation `callback`. The `callback` is bound to the `thisArg` value, if one is passed. The `callback` is invoked with `3` arguments; for arrays they are *(value, index, array)* and for objects they are *(value, key, object)*. +Produces a new array of values by mapping each value in the `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 *(value, key, object)*. #### Arguments 1. `collection` *(Array|Object)*: The collection to iterate over. -2. `callback` *(Function)*: The function called per iteration. +2. `[callback=identity]` *(Function)*: The function called per iteration. 3. `[thisArg]` *(Mixed)*: The `this` binding for the callback. #### Returns @@ -1460,7 +1540,7 @@ _.map([1, 2, 3], function(num) { return num * 3; }); // => [3, 6, 9] _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; }); -// => [3, 6, 9] +// => [3, 6, 9] (order is not guaranteed) ~~~ * * * @@ -1471,9 +1551,9 @@ _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; }); ### `_.max(array [, callback, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1266 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1347 "View in source") [Ⓣ][1] -Retrieves the maximum value of an `array`. If `callback` is passed, it will be executed for each value in the `array` to generate the criterion by which the value is ranked. The `callback` is invoked with `3` arguments; *(value, index, array)*. +Retrieves the maximum value of an `array`. If `callback` is passed, it will be executed for each value in the `array` to generate the criterion by which the value is ranked. The `callback` is bound to `thisArg` and invoked with `3` arguments; *(value, index, array)*. #### Arguments 1. `array` *(Array)*: The array to iterate over. @@ -1503,7 +1583,7 @@ _.max(stooges, function(stooge) { return stooge.age; }); ### `_.memoize(func [, resolver])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1897 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2018 "View in source") [Ⓣ][1] Creates a new function that memoizes the result of `func`. If `resolver` is passed, it will be used to determine the cache key for storing the result based on the arguments passed to the memoized function. By default, the first argument passed to the memoized function is used as the cache key. @@ -1529,9 +1609,9 @@ var fibonacci = _.memoize(function(n) { ### `_.min(array [, callback, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1312 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1393 "View in source") [Ⓣ][1] -Retrieves the minimum value of an `array`. If `callback` is passed, it will be executed for each value in the `array` to generate the criterion by which the value is ranked. The `callback` is invoked with `3` arguments; *(value, index, array)*. +Retrieves the minimum value of an `array`. If `callback` is passed, it will be executed for each value in the `array` to generate the criterion by which the value is ranked. The `callback` is bound to `thisArg` and invoked with `3` arguments; *(value, index, array)*. #### Arguments 1. `array` *(Array)*: The array to iterate over. @@ -1555,7 +1635,7 @@ _.min([10, 5, 100, 2, 1000]); ### `_.mixin(object)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2793 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2959 "View in source") [Ⓣ][1] Adds functions properties of `object` to the `lodash` function and chainable wrapper. @@ -1585,7 +1665,7 @@ _('larry').capitalize(); ### `_.noConflict()` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2824 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2990 "View in source") [Ⓣ][1] Reverts the '_' variable to its previous value and returns a reference to the `lodash` function. @@ -1605,7 +1685,7 @@ var lodash = _.noConflict(); ### `_.once(func)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1923 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2044 "View in source") [Ⓣ][1] Creates a new function that is restricted to one execution. Repeat calls to the function will return the value of the first call. @@ -1631,7 +1711,7 @@ initialize(); ### `_.partial(func [, arg1, arg2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1956 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2077 "View in source") [Ⓣ][1] Creates a new function that, when called, invokes `func` with any additional `partial` arguments prepended to those passed to the partially applied function. This method is similar `bind`, except it does **not** alter the `this` binding. @@ -1658,7 +1738,7 @@ hi('moe'); ### `_.pick(object [, prop1, prop2, ...])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2653 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2826 "View in source") [Ⓣ][1] Creates an object composed of the specified properties. Property names may be specified as individual arguments or as arrays of property names. @@ -1683,7 +1763,7 @@ _.pick({ 'name': 'moe', 'age': 40, 'userid': 'moe1' }, 'name', 'age'); ### `_.pluck(collection, property)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L665 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L733 "View in source") [Ⓣ][1] Retrieves the value of a specified property from all values in a `collection`. @@ -1714,7 +1794,7 @@ _.pluck(stooges, 'name'); ### `_.range([start=0], end [, step=1])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1369 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1450 "View in source") [Ⓣ][1] Creates an array of numbers *(positive and/or negative)* progressing from `start` up to but not including `stop`. This method is a port of Python's `range()` function. See http://docs.python.org/library/functions.html#range. @@ -1752,9 +1832,9 @@ _.range(0); ### `_.reduce(collection, callback [, accumulator, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L695 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L762 "View in source") [Ⓣ][1] -Boils down a `collection` to a single value. The initial state of the reduction is `accumulator` and each successive step of it should be returned by the `callback`. The `callback` is bound to the `thisArg` value, if one is passed. The `callback` is invoked with `4` arguments; for arrays they are *(accumulator, value, index, array)* and for objects they are *(accumulator, value, key, object)*. +Boils down a `collection` to a single value. The initial state of the reduction is `accumulator` and each successive step of it should be returned by the `callback`. The `callback` is bound to `thisArg` and invoked with `4` arguments; for arrays they are *(accumulator, value, index, array)* and for objects they are *(accumulator, value, key, object)*. #### Arguments 1. `collection` *(Array|Object)*: The collection to iterate over. @@ -1779,9 +1859,9 @@ var sum = _.reduce([1, 2, 3], function(memo, num) { return memo + num; }); ### `_.reduceRight(collection, callback [, accumulator, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L735 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L799 "View in source") [Ⓣ][1] -The right-associative version of `_.reduce`. The `callback` is bound to the `thisArg` value, if one is passed. The `callback` is invoked with `4` arguments; for arrays they are *(accumulator, value, index, array)* and for objects they are *(accumulator, value, key, object)*. +The right-associative version of `_.reduce`. #### Arguments 1. `collection` *(Array|Object)*: The collection to iterate over. @@ -1806,14 +1886,14 @@ var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []); -### `_.reject(collection, callback [, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L788 "View in source") [Ⓣ][1] +### `_.reject(collection [, callback=identity, thisArg])` +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L850 "View in source") [Ⓣ][1] -The opposite of `_.filter`, this method returns the values of a `collection` that `callback` does **not** return truthy for. The `callback` is invoked with `3` arguments; for arrays they are *(value, index, array)* and for objects they are *(value, key, object)*. +The opposite of `_.filter`, this method returns the values of a `collection` that `callback` does **not** return truthy for. #### Arguments 1. `collection` *(Array|Object)*: The collection to iterate over. -2. `callback` *(Function)*: The function called per iteration. +2. `[callback=identity]` *(Function)*: The function called per iteration. 3. `[thisArg]` *(Mixed)*: The `this` binding for the callback. #### Returns @@ -1833,7 +1913,7 @@ var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); ### `_.rest(array [, n, guard])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1405 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1486 "View in source") [Ⓣ][1] The opposite of `_.initial`, this method gets all but the first value of the `array`. Pass `n` to exclude the first `n` values from the result. @@ -1847,8 +1927,8 @@ The opposite of `_.initial`, this method gets all but the first value of the `ar #### Example ~~~ js -_.rest([5, 4, 3, 2, 1]); -// => [4, 3, 2, 1] +_.rest([3, 2, 1]); +// => [2, 1] ~~~ * * * @@ -1859,9 +1939,9 @@ _.rest([5, 4, 3, 2, 1]); ### `_.result(object, property)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2854 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L3020 "View in source") [Ⓣ][1] -Resolves the value of `property` on `object`. If the property is a function it will be invoked and its result returned, else the property value is returned. +Resolves the value of `property` on `object`. If `property` is a function it will be invoked and its result returned, else the property value is returned. #### Arguments 1. `object` *(Object)*: The object to inspect. @@ -1894,7 +1974,7 @@ _.result(object, 'stuff'); ### `_.shuffle(array)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1423 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1504 "View in source") [Ⓣ][1] Produces a new array of shuffled `array` values, using a version of the Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle. @@ -1918,15 +1998,15 @@ _.shuffle([1, 2, 3, 4, 5, 6]); ### `_.size(value)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2692 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2865 "View in source") [Ⓣ][1] -Gets the size of a `value` by returning `value.length` if `value` is a string or array, or the number of own enumerable properties if `value` is an object. +Gets the size of a `value` by returning `value.length` if `value` is a string or array, or the number of enumerable own properties if `value` is an object. #### Arguments 1. `value` *(Array|Object|String)*: The value to inspect. #### Returns -*(Number)*: Returns `value.length` if `value` is a string or array, or the number of own enumerable properties if `value` is an object. +*(Number)*: Returns `value.length` if `value` is a string or array, or the number of enumerable own properties if `value` is an object. #### Example ~~~ js @@ -1947,14 +2027,14 @@ _.size('curly'); -### `_.some(collection, callback [, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L812 "View in source") [Ⓣ][1] +### `_.some(collection [, callback=identity, thisArg])` +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L874 "View in source") [Ⓣ][1] -Checks if the `callback` returns a truthy value for **any** element of a `collection`. The function returns as soon as it finds passing value, and does not iterate over the entire `collection`. The `callback` is invoked with `3` arguments; for arrays they are *(value, index, array)* and for objects they are *(value, key, object)*. +Checks if the `callback` returns a truthy value for **any** element of a `collection`. The function returns as soon as it finds passing value, and does not iterate over the entire `collection`. The `callback` is bound to `thisArg` and invoked with `3` arguments; for arrays they are *(value, index, array)* and for objects they are *(value, key, object)*. #### Arguments 1. `collection` *(Array|Object)*: The collection to iterate over. -2. `callback` *(Function)*: The function called per iteration. +2. `[callback=identity]` *(Function)*: The function called per iteration. 3. `[thisArg]` *(Mixed)*: The `this` binding for the callback. #### Returns @@ -1974,9 +2054,9 @@ _.some([null, 0, 'yes', false]); ### `_.sortBy(array, callback [, thisArg])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1051 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1115 "View in source") [Ⓣ][1] -Produces a new sorted array, ranked in ascending order by the results of running each value of a `collection` through `callback`. The `callback` is invoked with `3` arguments; for arrays they are *(value, index, array)* and for objects they are *(value, key, object)*. The `callback` argument may also be the name of a property to sort by *(e.g. 'length')*. +Produces a new sorted array, ranked in ascending order by the results of running each element of `array` through `callback`. The `callback` is bound to `thisArg` and invoked with `3` arguments; *(value, index, array)*. The `callback` argument may also be the name of a property to sort by *(e.g. 'length')*. #### Arguments 1. `array` *(Array)*: The array to iterate over. @@ -1988,11 +2068,14 @@ Produces a new sorted array, ranked in ascending order by the results of running #### Example ~~~ js -_.sortBy([1, 2, 3, 4, 5, 6], function(num) { return Math.sin(num); }); -// => [5, 4, 6, 3, 1, 2] +_.sortBy([1, 2, 3], function(num) { return Math.sin(num); }); +// => [3, 1, 2] + +_.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math); +// => [3, 1, 2] -_.sortBy([1, 2, 3, 4, 5, 6], function(num) { return this.sin(num); }, Math); -// => [5, 4, 6, 3, 1, 2] +_.sortBy(['larry', 'brendan', 'moe'], 'length'); +// => ['moe', 'larry', 'brendan'] ~~~ * * * @@ -2002,23 +2085,38 @@ _.sortBy([1, 2, 3, 4, 5, 6], function(num) { return this.sin(num); }, Math); -### `_.sortedIndex(array, value [, callback])` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L1457 "View in source") [Ⓣ][1] +### `_.sortedIndex(array, value [, callback=identity, thisArg])` +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L1553 "View in source") [Ⓣ][1] -Uses a binary search to determine the smallest index at which the `value` should be inserted into the `collection` in order to maintain the sort order of the `collection`. If `callback` is passed, it will be executed for each value in the `collection` to compute their sort ranking. The `callback` is invoked with `1` argument; *(value)*. +Uses a binary search to determine the smallest index at which the `value` should be inserted into the `array` in order to maintain the sort order of the sorted `array`. If `callback` is passed, it will be executed for `value` and each element in the `array` to compute their sort ranking. The `callback` is bound to `thisArg` and invoked with `1` argument; *(value)*. #### Arguments 1. `array` *(Array)*: The array to iterate over. 2. `value` *(Mixed)*: The value to evaluate. -3. `[callback]` *(Function)*: The function called per iteration. +3. `[callback=identity]` *(Function)*: The function called per iteration. +4. `[thisArg]` *(Mixed)*: The `this` binding for the callback. #### Returns -*(Number)*: Returns the index at which the value should be inserted into the collection. +*(Number)*: Returns the index at which the value should be inserted into the array. #### Example ~~~ js -_.sortedIndex([10, 20, 30, 40, 50], 35); -// => 3 +_.sortedIndex([20, 30, 40], 35); +// => 2 + +var dict = { + 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'thirty-five': 35, 'fourty': 40 } +}; + +_.sortedIndex(['twenty', 'thirty', 'fourty'], 'thirty-five', function(word) { + return dict.wordToNumber[word]; +}); +// => 2 + +_.sortedIndex(['twenty', 'thirty', 'fourty'], 'thirty-five', function(word) { + return this.wordToNumber[word]; +}, dict); +// => 2 ~~~ * * * @@ -2029,7 +2127,7 @@ _.sortedIndex([10, 20, 30, 40, 50], 35); ### `_.tap(value, interceptor)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2720 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L2893 "View in source") [Ⓣ][1] Invokes `interceptor` with the `value` as the first argument, and then returns `value`. The primary purpose of this method is to "tap into" a method chain, in order to performoperations on intermediate results within the chain. @@ -2059,7 +2157,7 @@ _.chain([1,2,3,200]) ### `_.template(text, data, options)` -# [Ⓢ](https://github.com/bestiejs/lodash/blob/master/lodash.js#L2914 "View in source") [Ⓣ][1] +# [Ⓢ](https://github.com/bestiejs/lodash/blob/v0.3.0/lodash.js#L3079 "View in source") [Ⓣ][1] A JavaScript micro-templating method, similar to John Resig's implementation. Lo-Dash templating handles arbitrary delimiters, preserves whitespace, and correctly escapes quotes within interpolated code. @@ -2078,13 +2176,13 @@ var compiled = _.template('hello: <%= name %>'); compiled({ 'name': 'moe' }); // => 'hello: moe' -var list = '% _.forEach(people, function(name) { %>
  • <%= name %>
  • <% }); %>'; +var list = '<% _.forEach(people, function(name) { %>
  • <%= name %>
  • <% }); %>'; _.template(list, { 'people': ['moe', 'curly', 'larry'] }); // => '
  • moe
  • curly
  • larry
  • ' var template = _.template('<%- value %>'); template({ 'value': ' diff --git a/perf/perf.js b/perf/perf.js index bfebe3cf77..e3f20c9d81 100644 --- a/perf/perf.js +++ b/perf/perf.js @@ -25,6 +25,11 @@ _._ || _ ); + /** Used to access the Firebug Lite panel */ + var fbPanel = (fbPanel = window.document && document.getElementById('FirebugUI')) && + (fbPanel = (fbPanel = fbPanel.contentWindow || fbPanel.contentDocument).document || fbPanel) && + fbPanel.getElementById('fbPanel1'); + /** Used to score Lo-Dash and Underscore performance */ var score = { 'lodash': 0, 'underscore': 0 }; @@ -41,6 +46,22 @@ /*--------------------------------------------------------------------------*/ + /** + * Logs text to the console. + * + * @private + * @param {String} text The text to log. + */ + function log(text) { + console.log(text); + if (fbPanel) { + // scroll the Firebug Lite panel down + fbPanel.scrollTop = fbPanel.scrollHeight; + } + } + + /*--------------------------------------------------------------------------*/ + lodash.extend(Benchmark.options, { 'async': true, 'setup': function() { @@ -48,16 +69,12 @@ _ = window._, lodash = window.lodash; - var numbers = [], + var length = 20, + numbers = [], object = {}, fourNumbers = [5, 25, 10, 30], nestedNumbers = [1, [2], [3, [[4]]]], - twoNumbers = [12, 21], - words = [ - 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', - 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', - 'seventeen', 'eighteen', 'nineteen', 'twenty' - ]; + twoNumbers = [12, 21]; var ctor = function() { }, func = function(greeting) { return greeting + ': ' + this.name; }; @@ -70,40 +87,71 @@ _boundCtor = _.bind(ctor, { 'name': 'moe' }), _boundPartial = _.bind(func, { 'name': 'moe' }, 'hi'); - for (var index = 0; index < 20; index++) { + var wordToNumber = { + 'one': 1, + 'two': 2, + 'three': 3, + 'four': 4, + 'five': 5, + 'six': 6, + 'seven': 7, + 'eight': 8, + 'nine': 9, + 'ten': 10, + 'eleven': 11, + 'twelve': 12, + 'thirteen': 13, + 'fourteen': 14, + 'fifteen': 15, + 'sixteen': 16, + 'seventeen': 17, + 'eighteen': 18, + 'nineteen': 19, + 'twenty': 20, + 'twenty-one': 21, + 'twenty-two': 22, + 'twenty-three': 23, + 'twenty-four': 24, + 'twenty-five': 25 + }; + + var words = _.keys(wordToNumber).slice(0, length); + + for (var index = 0; index < length; index++) { numbers[index] = index; object['key' + index] = index; } - var objects = lodash.map(numbers, function(n) { - return { 'num': n }; + var objects = lodash.map(numbers, function(num) { + return { 'num': num }; }); } }); lodash.extend(Benchmark.Suite.options, { 'onStart': function() { - console.log('\n' + this.name + ':'); + log('\n' + this.name + ':'); }, 'onCycle': function(event) { - console.log(event.target + ''); + log(event.target + ''); }, 'onComplete': function() { - var fastest = this.filter('fastest'), + var formatNumber = Benchmark.formatNumber, + fastest = this.filter('fastest'), slowest = this.filter('slowest'), lodashHz = 1 / (this[0].stats.mean + this[0].stats.moe), underscoreHz = 1 / (this[1].stats.mean + this[1].stats.moe); if (fastest.length > 1) { - console.log('It\'s too close to call.'); + log('It\'s too close to call.'); lodashHz = underscoreHz = Math.min(lodashHz, underscoreHz); } else { var fastestHz = fastest[0] == this[0] ? lodashHz : underscoreHz, slowestHz = slowest[0] == this[0] ? lodashHz : underscoreHz, - percent = Math.round(((fastestHz / slowestHz) - 1) * 100); + percent = formatNumber(Math.round(((fastestHz / slowestHz) - 1) * 100)); - console.log(fastest[0].name + ' is ' + percent + '% faster.'); + log(fastest[0].name + ' is ' + percent + '% faster.'); } // add score adjusted for margin of error score.lodash += lodashHz; @@ -119,15 +167,15 @@ else { var fastestTotalHz = Math.max(score.lodash, score.underscore), slowestTotalHz = Math.min(score.lodash, score.underscore), - totalPercent = Math.round(((fastestTotalHz / slowestTotalHz) - 1) * 100), - totalX = (fastestTotalHz / slowestTotalHz).toFixed(2), - message = ' is ' + totalPercent + '% (' + totalX + 'x) faster than '; + totalPercent = formatNumber(Math.round(((fastestTotalHz / slowestTotalHz) - 1) * 100)), + totalX = fastestTotalHz / slowestTotalHz, + message = ' is ' + totalPercent + '% ' + (totalX == 1 ? '' : '(' + formatNumber(totalX.toFixed(2)) + 'x) ') + 'faster than '; // report results if (score.lodash >= score.underscore) { - console.log('\nLo-Dash' + message + 'Underscore.'); + log('\nLo-Dash' + message + 'Underscore.'); } else { - console.log('\nUnderscore' + message + 'Lo-Dash.'); + log('\nUnderscore' + message + 'Lo-Dash.'); } } } @@ -146,7 +194,7 @@ ); suites.push( - Benchmark.Suite('bound normal') + Benchmark.Suite('bound') .add('Lo-Dash', function() { lodashBoundNormal(); }) @@ -180,31 +228,43 @@ suites.push( Benchmark.Suite('each array') .add('Lo-Dash', function() { - var timesTwo = []; - lodash.each(numbers, function(num) { - timesTwo.push(num * 2); - }); + var result = []; + lodash.each(numbers, function(num) { result.push(num * 2); }); }) .add('Underscore', function() { - var timesTwo = []; - _.each(numbers, function(num) { - timesTwo.push(num * 2); - }); + var result = []; + _.each(numbers, function(num) { result.push(num * 2); }); + }) + ); + + suites.push( + Benchmark.Suite('each array thisArg') + .add('Lo-Dash', function() { + var result = []; + lodash.each(numbers, function(num, index) { + result.push(num + this['key' + index]); + }, object); + }) + .add('Underscore', function() { + var result = []; + _.each(numbers, function(num, index) { + result.push(num + this['key' + index]); + }, object); }) ); suites.push( Benchmark.Suite('each object') .add('Lo-Dash', function() { - var timesTwo = []; + var result = []; lodash.each(object, function(num) { - timesTwo.push(num * 2); + result.push(num * 2); }); }) .add('Underscore', function() { - var timesTwo = []; + var result = []; _.each(object, function(num) { - timesTwo.push(num * 2); + result.push(num * 2); }); }) ); @@ -264,10 +324,10 @@ suites.push( Benchmark.Suite('groupBy callback') .add('Lo-Dash', function() { - lodash.groupBy(numbers, function(num) { return Math.floor(num); }); + lodash.groupBy(numbers, function(num) { return num >> 1; }); }) .add('Underscore', function() { - _.groupBy(numbers, function(num) { return Math.floor(num); }); + _.groupBy(numbers, function(num) { return num >> 1; }); }) ); @@ -283,6 +343,28 @@ /*--------------------------------------------------------------------------*/ + suites.push( + Benchmark.Suite('indexOf') + .add('Lo-Dash', function() { + lodash.indexOf(numbers, 9); + }) + .add('Underscore', function() { + _.indexOf(numbers, 9); + }) + ); + + suites.push( + Benchmark.Suite('indexOf isSorted') + .add('Lo-Dash', function() { + lodash.indexOf(numbers, 19, true); + }) + .add('Underscore', function() { + _.indexOf(numbers, 19, true); + }) + ); + + /*--------------------------------------------------------------------------*/ + suites.push( Benchmark.Suite('intersection') .add('Lo-Dash', function() { @@ -307,20 +389,46 @@ /*--------------------------------------------------------------------------*/ + suites.push( + Benchmark.Suite('lastIndexOf') + .add('Lo-Dash', function() { + lodash.lastIndexOf(numbers, 9); + }) + .add('Underscore', function() { + _.lastIndexOf(numbers, 9); + }) + ); + + /*--------------------------------------------------------------------------*/ + suites.push( Benchmark.Suite('map') .add('Lo-Dash', function() { - lodash.map(objects, function(obj) { - return obj.num; + lodash.map(objects, function(value) { + return value.num; }); }) .add('Underscore', function() { - _.map(objects, function(obj) { - return obj.num; + _.map(objects, function(value) { + return value.num; }); }) ); + suites.push( + Benchmark.Suite('map thisArg') + .add('Lo-Dash', function() { + lodash.map(objects, function(value, index) { + return this['key' + index] + value.num; + }, object); + }) + .add('Underscore', function() { + _.map(objects, function(value, index) { + return this['key' + index] + value.num; + }, object); + }) + ); + /*--------------------------------------------------------------------------*/ suites.push( @@ -371,6 +479,90 @@ /*--------------------------------------------------------------------------*/ + suites.push( + Benchmark.Suite('sortBy callback') + .add('Lo-Dash', function() { + lodash.sortBy(numbers, function(num) { return Math.sin(num); }); + }) + .add('Underscore', function() { + _.sortBy(numbers, function(num) { return Math.sin(num); }); + }) + ); + + suites.push( + Benchmark.Suite('sortBy callback thisArg') + .add('Lo-Dash', function() { + lodash.sortBy(numbers, function(num) { return this.sin(num); }, Math); + }) + .add('Underscore', function() { + _.sortBy(numbers, function(num) { return this.sin(num); }, Math); + }) + ); + + suites.push( + Benchmark.Suite('sortBy property name') + .add('Lo-Dash', function() { + lodash.sortBy(words, 'length'); + }) + .add('Underscore', function() { + _.sortBy(words, 'length'); + }) + ); + + /*--------------------------------------------------------------------------*/ + + suites.push( + Benchmark.Suite('sortedIndex') + .add('Lo-Dash', function() { + lodash.sortedIndex(numbers, 25); + }) + .add('Underscore', function() { + _.sortedIndex(numbers, 25); + }) + ); + + suites.push( + Benchmark.Suite('sortedIndex callback') + .add('Lo-Dash', function() { + lodash.sortedIndex(words, 'twenty-five', function(value) { + return wordToNumber[value]; + }); + }) + .add('Underscore', function() { + _.sortedIndex(words, 'twenty-five', function(value) { + return wordToNumber[value]; + }); + }) + ); + + /*--------------------------------------------------------------------------*/ + + suites.push( + Benchmark.Suite('times') + .add('Lo-Dash', function() { + var result = []; + lodash.times(length, function(n) { result.push(n); }); + }) + .add('Underscore', function() { + var result = []; + _.times(length, function(n) { result.push(n); }); + }) + ); + + suites.push( + Benchmark.Suite('times thisArg') + .add('Lo-Dash', function() { + var result = []; + lodash.times(length, function(n) { result.push(this.sin(n)); }, Math); + }) + .add('Underscore', function() { + var result = []; + _.times(length, function(n) { result.push(this.sin(n)); }, Math); + }) + ); + + /*--------------------------------------------------------------------------*/ + suites.push( Benchmark.Suite('union') .add('Lo-Dash', function() { @@ -383,6 +575,32 @@ /*--------------------------------------------------------------------------*/ + suites.push( + Benchmark.Suite('uniq') + .add('Lo-Dash', function() { + lodash.uniq(numbers.concat(fourNumbers, twoNumbers)); + }) + .add('Underscore', function() { + _.uniq(numbers.concat(fourNumbers, twoNumbers)); + }) + ); + + suites.push( + Benchmark.Suite('uniq callback') + .add('Lo-Dash', function() { + lodash.uniq(numbers.concat(fourNumbers, twoNumbers), function(num) { + return num % 2; + }); + }) + .add('Underscore', function() { + _.uniq(numbers.concat(fourNumbers, twoNumbers), function(num) { + return num % 2; + }); + }) + ); + + /*--------------------------------------------------------------------------*/ + suites.push( Benchmark.Suite('values') .add('Lo-Dash', function() { @@ -396,9 +614,10 @@ /*--------------------------------------------------------------------------*/ if (Benchmark.platform + '') { - console.log(Benchmark.platform + ''); + log(Benchmark.platform + ''); } // start suites + log('\nSit back and relax, this may take a while.'); suites[0].run(); }(typeof global == 'object' && global || this)); diff --git a/test/test.js b/test/test.js index e98c8ab091..b62b26227d 100644 --- a/test/test.js +++ b/test/test.js @@ -37,6 +37,17 @@ 'valueOf': 7 }; + /** Used to check problem JScript properties too */ + var shadowedKeys = [ + 'constructor', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'toLocaleString', + 'toString', + 'valueOf' + ]; + /*--------------------------------------------------------------------------*/ /** @@ -142,6 +153,10 @@ test('should not escape the ">" character', function() { equal(_.escape('>'), '>'); }); + + test('should not escape the "/" character', function() { + equal(_.escape('/'), '/'); + }); }()); /*--------------------------------------------------------------------------*/ @@ -177,14 +192,14 @@ QUnit.module('lodash.find'); (function() { - var array = [1, 2, 3, 4]; + var array = [1, 2, 3]; test('should return found `value`', function() { equal(_.find(array, function(n) { return n > 2; }), 3); }); test('should return `undefined` if `value` is not found', function() { - equal(_.find(array, function(n) { return n == 5; }), undefined); + equal(_.find(array, function(n) { return n == 4; }), undefined); }); }()); @@ -215,22 +230,79 @@ (function() { test('returns the collection', function() { - var collection = [1, 2, 3, 4]; + var collection = [1, 2, 3]; equal(_.forEach(collection, Boolean), collection); }); - test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() { - var object = {}; - _.forEach(shadowed, function(value, key) { - object[key] = value; - }); + test('should treat array-like object with invalid `length` as a regular object', function() { + var keys = [], + object = { 'length': -1 }; + + _.forEach(object, function(value, key) { keys.push(key); }); + deepEqual(keys, ['length']); + }); + }()); - deepEqual(object, shadowed); + /*--------------------------------------------------------------------------*/ + + QUnit.module('lodash.forIn'); + + (function() { + test('iterates over inherited properties', function() { + function Dog(name) { this.name = name; } + Dog.prototype.bark = function() { /* Woof, woof! */ }; + + var keys = []; + _.forIn(new Dog('Dagny'), function(value, key) { keys.push(key); }); + deepEqual(keys.sort(), ['bark', 'name']); }); }()); /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.forOwn'); + + (function() { + test('iterates over the `length` property', function() { + var keys = [], + object = { '0': 'zero', '1': 'one', 'length': 2 }; + + _.forOwn(object, function(value, key) { keys.push(key); }); + deepEqual(keys.sort(), ['0', '1', 'length']); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + _.each(['forEach', 'forIn', 'forOwn'], function(methodName) { + var func = _[methodName]; + QUnit.module('lodash.' + methodName + ' iteration bugs'); + + test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() { + var keys = []; + func(shadowed, function(value, key) { keys.push(key); }); + deepEqual(keys.sort(), shadowedKeys); + }); + + test('skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', function() { + function Foo() {} + Foo.prototype.a = 1; + + var keys = []; + function callback(value, key) { keys.push(key); } + + func(Foo, callback); + deepEqual(keys, []); + keys.length = 0; + + Foo.prototype = { 'a': 1 }; + func(Foo, callback); + deepEqual(keys, []); + }); + }); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.groupBy'); (function() { @@ -254,11 +326,47 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.indexOf'); + + (function() { + var array = [1, 2, 3, 1, 2, 3]; + + test('should work with a positive `fromIndex`', function() { + equal(_.indexOf(array, 1, 2), 3); + }); + + test('should work with `fromIndex` >= `array.length`', function() { + equal(_.indexOf(array, 1, 6), -1); + equal(_.indexOf(array, undefined, 6), -1); + equal(_.indexOf(array, 1, 8), -1); + equal(_.indexOf(array, undefined, 8), -1); + }); + + test('should work with a negative `fromIndex`', function() { + equal(_.indexOf(array, 2, -3), 4); + }); + + test('should work with a negative `fromIndex` <= `-array.length`', function() { + equal(_.indexOf(array, 1, -6), 0); + equal(_.indexOf(array, 2, -8), 1); + }); + + test('should ignore non-number `fromIndex` values', function() { + equal(_.indexOf([1, 2, 3], 1, '1'), 0); + }); + + test('should work with `isSorted`', function() { + equal(_.indexOf([1, 2, 3], 1, true), 0); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.initial'); (function() { test('returns an empty collection for `n` of `0`', function() { - var array = [1, 2, 3, 4]; + var array = [1, 2, 3]; deepEqual(_.initial(array, 0), []); }); }()); @@ -271,6 +379,15 @@ test('fixes the JScript [[DontEnum]] bug (test in IE < 9)', function() { equal(_.isEmpty(shadowed), false); }); + + test('skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', function() { + function Foo() {} + Foo.prototype.a = 1; + equal(_.isEmpty(Foo), true); + + Foo.prototype = { 'a': 1 }; + equal(_.isEmpty(Foo), true); + }); }()); /*--------------------------------------------------------------------------*/ @@ -303,8 +420,54 @@ Foo.prototype.a = 1; deepEqual(_.keys(Foo.prototype), ['a']); - deepEqual(_.keys(shadowed).sort(), - 'constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf'.split(' ')); + deepEqual(_.keys(shadowed).sort(), shadowedKeys); + }); + + test('skips the prototype property of functions (test in Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1)', function() { + function Foo() {} + Foo.prototype.c = 3; + + Foo.a = 1; + Foo.b = 2; + + var expected = ['a', 'b']; + deepEqual(_.keys(Foo), expected); + + Foo.prototype = { 'c': 3 }; + deepEqual(_.keys(Foo), expected); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('lodash.lastIndexOf'); + + (function() { + var array = [1, 2, 3, 1, 2, 3]; + + test('should work with a positive `fromIndex`', function() { + equal(_.lastIndexOf(array, 1, 2), 0); + }); + + test('should work with `fromIndex` >= `array.length`', function() { + equal(_.lastIndexOf(array, undefined, 6), -1); + equal(_.lastIndexOf(array, 1, 6), 3); + equal(_.lastIndexOf(array, undefined, 8), -1); + equal(_.lastIndexOf(array, 1, 8), 3); + }); + + test('should work with a negative `fromIndex`', function() { + equal(_.lastIndexOf(array, 2, -3), 1); + }); + + test('should work with a negative `fromIndex` <= `-array.length`', function() { + equal(_.lastIndexOf(array, 1, -6), 0); + equal(_.lastIndexOf(array, 2, -8), -1); + }); + + test('should ignore non-number `fromIndex` values', function() { + equal(_.lastIndexOf([1, 2, 3], 3, '1'), 2); + equal(_.lastIndexOf([1, 2, 3], 3, true), 2); }); }()); @@ -366,6 +529,17 @@ deepEqual(args, ['C', 'B', 'b', object]); }); + + test('should treat array-like object with invalid `length` as a regular object', function() { + var args, + object = { 'a': 'A', 'length': -1 }; + + _.reduceRight(object, function() { + args || (args = slice.call(arguments)); + }); + + deepEqual(args, [-1, 'A', 'a', object]); + }); }()); /*--------------------------------------------------------------------------*/ @@ -388,11 +562,36 @@ (function() { test('supports the `thisArg` argument', function() { - var actual = _.sortBy([1, 2, 3, 4], function(num) { + var actual = _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math); - deepEqual(actual, [4, 3, 1, 2]); + deepEqual(actual, [3, 1, 2]); + }); + }()); + + /*--------------------------------------------------------------------------*/ + + QUnit.module('lodash.sortedIndex'); + + (function() { + test('supports the `thisArg` argument', function() { + var actual = _.sortedIndex([1, 2, 3], 4, function(num) { + return this.sin(num); + }, Math); + + equal(actual, 0); + }); + + test('supports arrays with lengths larger than `Math.pow(2, 31) - 1`', function() { + var length = Math.pow(2, 32) - 1, + index = length - 1, + array = Array(length), + steps = 0; + + array[index] = index; + _.sortedIndex(array, index, function() { steps++; }); + equal(steps, 33); }); }()); @@ -453,15 +652,34 @@ deepEqual(_.toArray(array), [3, 2, 1]); }); - test('should treat array-like-objects like arrays', function() { + test('should treat array-like objects like arrays', function() { var object = { '0': 'a', '1': 'b', '2': 'c', 'length': 3 }; deepEqual(_.toArray(object), ['a', 'b', 'c']); deepEqual(_.toArray(args), [1, 2, 3]); }); + + test('should treat array-like object with invalid `length` as a regular object', function() { + var object = { 'length': -1 }; + deepEqual(_.toArray(object), [-1]); + }); }(1, 2, 3)); /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.uniq'); + + (function() { + test('supports the `thisArg` argument', function() { + var actual = _.uniq([1, 2, 1.5, 3, 2.5], function(num) { + return this.floor(num); + }, Math); + + deepEqual(actual, [1, 2, 3]); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash(...).shift'); (function() { diff --git a/vendor/backbone b/vendor/backbone index 5509e13842..85bd0b5132 160000 --- a/vendor/backbone +++ b/vendor/backbone @@ -1 +1 @@ -Subproject commit 5509e13842a4d8e9c2c2fd59d86492bbf6c0b596 +Subproject commit 85bd0b5132e0da853eda114bd761d7961b80a146 diff --git a/vendor/benchmark.js b/vendor/benchmark.js index f0306c0345..c304a20cd6 160000 --- a/vendor/benchmark.js +++ b/vendor/benchmark.js @@ -1 +1 @@ -Subproject commit f0306c03451a84b85b313410f3881b36bc935f39 +Subproject commit c304a20cd63b12d3439f6a60dc72192d7f626ed2 diff --git a/vendor/requirejs b/vendor/requirejs index 07de481552..42dba3d981 160000 --- a/vendor/requirejs +++ b/vendor/requirejs @@ -1 +1 @@ -Subproject commit 07de48155203931a763a7b954b016e8dbd1d26aa +Subproject commit 42dba3d9814bf3e901917dd31e464fa5145394fd diff --git a/vendor/uglifyjs b/vendor/uglifyjs index ef4d776aed..e87718e2d1 160000 --- a/vendor/uglifyjs +++ b/vendor/uglifyjs @@ -1 +1 @@ -Subproject commit ef4d776aedee6cbc8959a8e76403b82523615d3a +Subproject commit e87718e2d1835a3836d9e6e06f0f6e7e6458a298