diff --git a/README.md b/README.md index a6564a2a2..2b49cb4a0 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,88 @@ - __ - /\ \ __ - __ __ ___ \_\ \ __ _ __ ____ ___ ___ _ __ __ /\_\ ____ - /\ \/\ \ /' _ `\ /'_ \ /'__`\/\ __\/ ,__\ / ___\ / __`\/\ __\/'__`\ \/\ \ /',__\ - \ \ \_\ \/\ \/\ \/\ \ \ \/\ __/\ \ \//\__, `\/\ \__//\ \ \ \ \ \//\ __/ __ \ \ \/\__, `\ - \ \____/\ \_\ \_\ \___,_\ \____\\ \_\\/\____/\ \____\ \____/\ \_\\ \____\/\_\ _\ \ \/\____/ - \/___/ \/_/\/_/\/__,_ /\/____/ \/_/ \/___/ \/____/\/___/ \/_/ \/____/\/_//\ \_\ \/___/ - \ \____/ - \/___/ - -Underscore.js is a utility-belt library for JavaScript that provides -support for the usual functional suspects (each, map, reduce, filter...) -without extending any core JavaScript objects. +# Lo-Dash v0.1.0 -For Docs, License, Tests, and pre-packed downloads, see: -http://documentcloud.github.com/underscore/ +TBD -Many thanks to our contributors: -https://github.com/documentcloud/underscore/contributors +## BestieJS + +Lo-Dash is part of the BestieJS *"Best in Class"* module collection. This means we promote solid browser/environment support, ES5 precedents, unit testing, and plenty of documentation. + +## Documentation + +The documentation for Lo-Dash can be viewed here: [lodash/doc](https://github.com/bestiejs/lodash/doc/README.md) + +For a list of upcoming features, check out our [roadmap](https://github.com/bestiejs/lodash/wiki/Roadmap). + +## Installation and usage + +In a browser: + +~~~ html + +~~~ + +Via [npm](http://npmjs.org/): + +~~~ bash +npm install lodash +~~~ + +In [Node.js](http://nodejs.org/) and [RingoJS v0.8.0+](http://ringojs.org/): + +~~~ js +var _ = require('lodash'); +~~~ + +In [Narwhal](http://narwhaljs.org/) and [RingoJS v0.7.0-](http://ringojs.org/): + +~~~ js +var _ = require('lodash')._; +~~~ + +In [Rhino](http://www.mozilla.org/rhino/): + +~~~ js +load('lodash.js'); +~~~ + +In an AMD loader like [RequireJS](http://requirejs.org/): + +~~~ js +require({ + 'paths': { + 'lodash': 'path/to/lodash' + } +}, +['lodash'], function(_) { + console.log(_.VERSION); +}); +~~~ + +Usage example: + +~~~ js +// TBD +~~~ + +## Cloning this repo + +To clone this repository including all submodules, using Git 1.6.5 or later: + +~~~ bash +git clone --recursive https://github.com/bestiejs/lodash.git +cd lodash.js +~~~ + +For older Git versions, just use: + +~~~ bash +git clone https://github.com/bestiejs/lodash.git +cd lodash +git submodule update --init +~~~ + +Feel free to fork if you see possible improvements! + +## Author + +* [John-David Dalton](http://allyoucanleet.com/) + [![twitter/jdalton](http://gravatar.com/avatar/299a3d891ff1920b69c364d061007043?s=70)](https://twitter.com/jdalton "Follow @jdalton on Twitter") diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 000000000..6c1581137 --- /dev/null +++ b/doc/README.md @@ -0,0 +1,2131 @@ +# Lo-Dash v0.1.0 + + + + + + +## `_` +* [`_`](#_) +* [`_.VERSION`](#_.VERSION) +* [`_.after`](#_.after) +* [`_.bind`](#_.bind) +* [`_.bindAll`](#_.bindAll) +* [`_.chain`](#_.chain) +* [`_.clone`](#_.clone) +* [`_.compact`](#_.compact) +* [`_.compose`](#_.compose) +* [`_.contains`](#_.contains) +* [`_.debounce`](#_.debounce) +* [`_.defaults`](#_.defaults) +* [`_.defer`](#_.defer) +* [`_.delay`](#_.delay) +* [`_.difference`](#_.difference) +* [`_.escape`](#_.escape) +* [`_.every`](#_.every) +* [`_.extend`](#_.extend) +* [`_.filter`](#_.filter) +* [`_.find`](#_.find) +* [`_.first`](#_.first) +* [`_.flatten`](#_.flatten) +* [`_.forEach`](#_.forEach) +* [`_.functions`](#_.functions) +* [`_.groupBy`](#_.groupBy) +* [`_.has`](#_.has) +* [`_.identity`](#_.identity) +* [`_.indexOf`](#_.indexOf) +* [`_.initial`](#_.initial) +* [`_.intersection`](#_.intersection) +* [`_.invoke`](#_.invoke) +* [`_.isArguments`](#_.isArguments) +* [`_.isArray`](#_.isArray) +* [`_.isBoolean`](#_.isBoolean) +* [`_.isDate`](#_.isDate) +* [`_.isElement`](#_.isElement) +* [`_.isEmpty`](#_.isEmpty) +* [`_.isEqual`](#_.isEqual) +* [`_.isFinite`](#_.isFinite) +* [`_.isFunction`](#_.isFunction) +* [`_.isNaN`](#_.isNaN) +* [`_.isNull`](#_.isNull) +* [`_.isNumber`](#_.isNumber) +* [`_.isObject`](#_.isObject) +* [`_.isRegExp`](#_.isRegExp) +* [`_.isString`](#_.isString) +* [`_.isUndefined`](#_.isUndefined) +* [`_.keys`](#_.keys) +* [`_.last`](#_.last) +* [`_.lastIndexOf`](#_.lastIndexOf) +* [`_.map`](#_.map) +* [`_.max`](#_.max) +* [`_.memoize`](#_.memoize) +* [`_.min`](#_.min) +* [`_.mixin`](#_.mixin) +* [`_.noConflict`](#_.noConflict) +* [`_.once`](#_.once) +* [`_.pick`](#_.pick) +* [`_.pluck`](#_.pluck) +* [`_.range`](#_.range) +* [`_.reduce`](#_.reduce) +* [`_.reduceRight`](#_.reduceRight) +* [`_.reject`](#_.reject) +* [`_.rest`](#_.rest) +* [`_.result`](#_.result) +* [`_.shuffle`](#_.shuffle) +* [`_.size`](#_.size) +* [`_.some`](#_.some) +* [`_.sortBy`](#_.sortBy) +* [`_.sortedIndex`](#_.sortedIndex) +* [`_.tap`](#_.tap) +* [`_.template`](#_.template) +* [`_.throttle`](#_.throttle) +* [`_.times`](#_.times) +* [`_.toArray`](#_.toArray) +* [`_.union`](#_.union) +* [`_.uniq`](#_.uniq) +* [`_.uniqueId`](#_.uniqueId) +* [`_.values`](#_.values) +* [`_.without`](#_.without) +* [`_.wrap`](#_.wrap) +* [`_.zip`](#_.zip) + + + + + + +## `_.prototype` +* [`_#chain`](#_:chain) +* [`_#value`](#_:value) + + + + + + +## `_.templateSettings` +* [`_.templateSettings`](#_.templateSettings) + + + + + + + + + + + + +## `_` + + + +### `_(value)` +The Lodash function. +[▲][1] + +#### Arguments +1. `value` *(Mixed)*: The value to wrap in a chainable `lowdash` object. + +#### Returns +*(Object)*: Returns a `lodash` instance. + +#### Example +~~~ js + +~~~ + + + + + + +## `_` +### `_(value)` +The Lodash function. +[▲][1] + + + +### `_.VERSION` +*(String)*: The semantic version number. +[▲][1] + + + + + + +### `_.after(times, func)` +Creates a new function that is restricted to executing only after it is called a given number of `times`. +[▲][1] + +#### Arguments +1. `times` *(Number)*: The number of times the function must be called before it is executed. +2. `func` *(Function)*: The function to restrict. + +#### Returns +*(Function)*: Returns the new restricted function. + +#### Example +~~~ js +var renderNotes = _.after(notes.length, render); +_.forEach(notes, function(note) { + note.asyncSave({ 'success': renderNotes }); +}); +// renderNotes is run once, after all notes have saved. +~~~ + + + + + + +### `_.bind(func [, arg1, arg2, ...])` +Creates a new function that, when called, invokes `func` with the `this` binding of `thisArg` and prepends additional arguments to those passed to the bound function. +[▲][1] + +#### Arguments +1. `func` *(Function)*: The function to bind. +2. `[arg1, arg2, ...]` *(Mixed)*: Arguments to prepend to those passed to the bound function. + +#### Returns +*(Function)*: Returns the new bound function. + +#### Example +~~~ js +var func = function(greeting){ return greeting + ': ' + this.name; }; +func = _.bind(func, { 'name': 'moe' }, 'hi'); +func(); +// => 'hi: moe' +~~~ + + + + + + +### `_.bindAll(object [, methodName1, methodName2, ...])` +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. +[▲][1] + +#### Arguments +1. `object` *(Object)*: The object to bind and assign the bound methods to. +2. `[methodName1, methodName2, ...]` *(Mixed)*: Method names on the object to bind. + +#### Returns +*(Object)*: Returns the `object`. + +#### Example +~~~ js +var buttonView = { + 'label': 'lodash', + 'onClick': function() { alert('clicked: ' + this.label); }, + 'onHover': function() { console.log('hovering: ' + this.label); } +}; + +_.bindAll(buttonView); +jQuery('#lodash_button').on('click', buttonView.onClick); +// => When the button is clicked, `this.label` will have the correct value +~~~ + + + + + + +### `_.chain(value)` +Wraps the value in a `lodash` chainable object. +[▲][1] + +#### Arguments +1. `value` *(Mixed)*: The value to wrap. + +#### Returns +*(Object)*: Returns the `lodash` chainable object. + +#### Example +~~~ js +var stooges = [ + { 'name' : 'moe', 'age' : 40}, + { 'name' : 'larry', 'age' : 50}, + { 'name' : 'curly', 'age' : 60} +]; + +var youngest = _.chain(stooges) + .sortBy(function(stooge){ return stooge.age; }) + .map(function(stooge){ return stooge.name + ' is ' + stooge.age; }) + .first() + .value(); +// => 'moe is 40' +~~~ + + + + + + +### `_.clone(value)` +Create a shallow clone of the `value`. Any nested objects or arrays will be assigned by reference and not cloned. +[▲][1] + +#### Arguments +1. `value` *(Mixed)*: The value to clone. + +#### Returns +*(Mixed)*: Returns the cloned `value`. + +#### Example +~~~ js +_.clone({ 'name': 'moe' }); +// => { 'name': 'moe' }; +~~~ + + + + + + +### `_.compact(array)` +Produces a new array with all falsey values of `array` removed. The values `false`, `null`, `0`, `""`, `undefined` and `NaN` are all falsey. +[▲][1] + +#### Arguments +1. `array` *(Array)*: The array to compact. + +#### Returns +*(Array)*: Returns a new filtered array. + +#### Example +~~~ js +_.compact([0, 1, false, 2, '', 3]); +// => [1, 2, 3] +~~~ + + + + + + +### `_.compose([func1, func2, ...])` +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()))`. +[▲][1] + +#### Arguments +1. `[func1, func2, ...]` *(Mixed)*: Functions to compose. + +#### Returns +*(Function)*: Returns the new composed function. + +#### Example +~~~ js +var greet = function(name) { return 'hi: ' + name; }; +var exclaim = function(statement) { return statement + '!'; }; +var welcome = _.compose(exclaim, greet); +welcome('moe'); +// => 'hi: moe!' +~~~ + + + + + + +### `_.contains(collection, target)` +Checks if a given `target` value is present in a `collection` using strict equality for comparisons, i.e. `===`. +[▲][1] + +#### Arguments +1. `collection` *(Array|Object)*: The collection to iterate over. +2. `target` *(Mixed)*: The value to check for. + +#### Returns +*(Boolean)*: Returns `true` if `target` value is found, else `false`. + +#### Example +~~~ js +_.contains([1, 2, 3], 3); +// => true +~~~ + + + + + + +### `_.debounce(func, wait, immediate)` +Creates a new function that will postpone its execution until after `wait` milliseconds have elapsed since the last time it was invoked. Pass `true` for `immediate` to cause debounce to invoke the function on the leading, intead of the trailing, edge of the wait timeout. +[▲][1] + +#### Arguments +1. `func` *(Function)*: The function to debounce. +2. `wait` *(Number)*: The number of milliseconds to postone. +3. `immediate` *(Boolean)*: A flag to indicate execution is on the leading edge of the wait timeout. + +#### Returns +*(Function)*: Returns the new debounced function. + +#### Example +~~~ js +var lazyLayout = _.debounce(calculateLayout, 300); +jQuery(window).on('resize', lazyLayout); +~~~ + + + + + + +### `_.defaults(object [, defaults1, defaults2, ..])` +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. +[▲][1] + +#### Arguments +1. `object` *(Object)*: The object to populate. +2. `[defaults1, defaults2, ..]` *(Object)*: The defaults objects to apply to `object`. + +#### Returns +*(Object)*: Returns `object`. + +#### Example +~~~ js +var iceCream = { 'flavor': 'chocolate' }; +_.defaults(iceCream, { 'flavor': 'vanilla', 'sprinkles': 'lots' }); +// => { 'flavor': 'chocolate', 'sprinkles': 'lots' } +~~~ + + + + + + +### `_.defer(func [, arg1, arg2, ...])` +Defers invoking the `func` function until the current call stack has cleared. Additional arguments are passed to `func` when it is invoked. +[▲][1] + +#### Arguments +1. `func` *(Function)*: The function to defer. +2. `[arg1, arg2, ...]` *(Mixed)*: Arguments to invoke the function with. + +#### Returns +*(Number)*: Returns the `setTimeout` timeout id. + +#### Example +~~~ js +_.defer(function(){ alert('deferred'); }); +// Returns from the function before the alert runs. +~~~ + + + + + + +### `_.delay(func, wait [, arg1, arg2, ...])` +Invokes the `func` function after `wait` milliseconds. Additional arguments are passed `func` when it is invoked. +[▲][1] + +#### Arguments +1. `func` *(Function)*: The function to delay. +2. `wait` *(Number)*: The number of milliseconds to delay execution. +3. `[arg1, arg2, ...]` *(Mixed)*: Arguments to invoke the function with. + +#### Returns +*(Number)*: Returns the `setTimeout` timeout id. + +#### Example +~~~ js +var log = _.bind(console.log, console); +_.delay(log, 1000, 'logged later'); +// => 'logged later' (Appears after one second.) +~~~ + + + + + + +### `_.difference(array [, array1, array2, ...])` +Produces a new array of `array` values not present in the other arrays using strict equality for comparisons, i.e. `===`. +[▲][1] + +#### Arguments +1. `array` *(Array)*: The array to process. +2. `[array1, array2, ...]` *(Mixed)*: Arrays to check. + +#### Returns +*(Array)*: Returns a new array of `array` values not present in the other arrays. + +#### Example +~~~ js +_.difference([1, 2, 3, 4, 5], [5, 2, 10]); +// => [1, 3, 4] +~~~ + + + + + + +### `_.escape(string)` +Escapes a string for insertion into HTML, replacing `&`, `<`, `>`, `"`, `'`, and `/` characters. +[▲][1] + +#### Arguments +1. `string` *(String)*: The string to escape. + +#### Returns +*(String)*: Returns the escaped string. + +#### Example +~~~ js +_.escape('Curly, Larry & Moe'); +// => "Curly, Larry & Moe" +~~~ + + + + + + +### `_.every(collection, callback [, thisArg])` +Checks if the `callback` returns truthy for **all** values 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)*. +[▲][1] + +#### Arguments +1. `collection` *(Array|Object)*: The collection to iterate over. +2. `callback` *(Function)*: The function called per iteration. +3. `[thisArg]` *(Mixed)*: The `this` binding for the callback. + +#### Returns +*(Boolean)*: Returns `true` if all values pass the callback check, else `false`. + +#### Example +~~~ js +_.every([true, 1, null, 'yes'], Boolean); +=> false +~~~ + + + + + + +### `_.extend(destination [, source1, source2, ..])` +Copies enumerable properties from the source objects to the `destination` object. Subsequent sources will overwrite propery assignments of previous sources. +[▲][1] + +#### Arguments +1. `destination` *(Object)*: The destination object. +2. `[source1, source2, ..]` *(Object)*: The source objects. + +#### Returns +*(Object)*: Returns the `destination` object. + +#### Example +~~~ js +_.extend({ 'name': 'moe' }, { 'age': 40 }); +// => { 'name': 'moe', 'age': 40 } +~~~ + + + + + + +### `_.filter(collection, callback [, thisArg])` +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)*. +[▲][1] + +#### Arguments +1. `collection` *(Array|Object)*: The collection to iterate over. +2. `callback` *(Function)*: The function called per iteration. +3. `[thisArg]` *(Mixed)*: The `this` binding for the callback. + +#### Returns +*(Array)*: Returns a new array of values that passed callback check. + +#### Example +~~~ js +var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); +// => [2, 4, 6] +~~~ + + + + + + +### `_.find(collection, callback [, thisArg])` +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)*. +[▲][1] + +#### Arguments +1. `collection` *(Array|Object)*: The collection to iterate over. +2. `callback` *(Function)*: The function called per iteration. +3. `[thisArg]` *(Mixed)*: The `this` binding for the callback. + +#### Returns +*(Mixed)*: Returns the value that passed the callback check. + +#### Example +~~~ js +var even = _.find([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); +// => 2 +~~~ + + + + + + +### `_.first(array [, n, guard])` +Gets the first value of the `array`. Pass `n` to return the first `n` values of the `array`. +[▲][1] + +#### Arguments +1. `array` *(Array)*: The array to query. +2. `[n]` *(Number)*: The number of elements to return. +3. `[guard]` *(Object)*: Used to allow the function to work with other iteration methods like `_.map` without using their callback `index` argument for `n`. + +#### Returns +*(Mixed)*: Returns the first value or an array of the first `n` values of the `array`. + +#### Example +~~~ js +_.first([5, 4, 3, 2, 1]); +// => 5 +~~~ + + + + + + +### `_.flatten(array, shallow)` +Flattens a nested array *(the nesting can be to any depth)*. If `shallow` is truthy, `array` will only be flattened a single level. +[▲][1] + +#### Arguments +1. `array` *(Array)*: The array to compact. +2. `shallow` *(Boolean)*: A flag to indicate only flattening a single level. + +#### Returns +*(Array)*: Returns a new flattened array. + +#### Example +~~~ js +_.flatten([1, [2], [3, [[4]]]]); +// => [1, 2, 3, 4]; + +_.flatten([1, [2], [3, [[4]]]], true); +// => [1, 2, 3, [[4]]]; +~~~ + + + + + + +### `_.forEach(collection, callback [, thisArg])` +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)*. +[▲][1] + +#### Arguments +1. `collection` *(Array|Object)*: The collection to iterate over. +2. `callback` *(Function)*: The function called per iteration. +3. `[thisArg]` *(Mixed)*: The `this` binding for the callback. + +#### Returns +*(Array, Object)*: Returns the `collection`. + +#### Example +~~~ js +_.forforEach([1, 2, 3], function(num) { alert(num); }); +// => alerts each number in turn... + +_.forforEach({ 'one' : 1, 'two' : 2, 'three' : 3}, function(num) { alert(num); }); +// => alerts each number in turn... +~~~ + + + + + + +### `_.functions(object)` +Produces a sorted array of the `object`'s enumerable own property names that have function values. +[▲][1] + +#### Arguments +1. `object` *(Object)*: The object to inspect. + +#### Returns +*(Array)*: Returns a new array of property names that have function values. + +#### Example +~~~ js +_.functions(_); +// => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...] +~~~ + + + + + + +### `_.groupBy(collection, callback [, thisArg])` +Splits a `collection` into sets, grouped by the result of running each value 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 group by. +[▲][1] + +#### Arguments +1. `collection` *(Array|Object)*: The collection to iterate over. +2. `callback` *(Function|String)*: The function called per iteration or property name to group by. +3. `[thisArg]` *(Mixed)*: The `this` binding for the callback. + +#### Returns +*(Object)*: Returns an object of grouped values. + +#### Example +~~~ js +_.groupBy([1.3, 2.1, 2.4], function(num) { return Math.floor(num); }); +// => { '1': [1.3], '2': [2.1, 2.4] } + +_.groupBy(['one', 'two', 'three'], 'length'); +// => { '3': ['one', 'two'], '5': ['three'] } +~~~ + + + + + + +### `_.has(object, key)` +Checks if an object has the specified key as a direct property. +[▲][1] + +#### Arguments +1. `object` *(Object)*: The object to check. +2. `key` *(String)*: The key to check for. + +#### Returns +*(Boolean)*: Returns `true` if key is a direct property, else `false`. + +#### Example +~~~ js +_.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b'); +// => true +~~~ + + + + + + +### `_.identity(value)` +This function simply returns the first argument passed to it. Note: It is used throughout Lodash as a default callback. +[▲][1] + +#### Arguments +1. `value` *(Mixed)*: Any value. + +#### Returns +*(Mixed)*: Returns `value`. + +#### Example +~~~ js +var moe = { 'name': 'moe' }; +moe === _.identity(moe); +// => true +~~~ + + + + + + +### `_.indexOf(array, value [, isSorted=false])` +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. +[▲][1] + +#### 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. + +#### Returns +*(Number)*: Returns the index of the matched value or `-1`. + +#### Example +~~~ js +_.indexOf([1, 2, 3], 2); +// => 1 +~~~ + + + + + + +### `_.initial(array [, n, guard])` +Gets all but the last value of the `array`. Pass `n` to exclude the last `n` values from the result. +[▲][1] + +#### Arguments +1. `array` *(Array)*: The array to query. +2. `[n]` *(Number)*: The number of elements to return. +3. `[guard]` *(Object)*: Used to allow the function to work with other iteration methods like `_.map` without using their callback `index` argument for `n`. + +#### Returns +*(Array)*: Returns all but the last value or `n` values of the `array`. + +#### Example +~~~ js +_.initial([5, 4, 3, 2, 1]); +// => [5, 4, 3, 2] +~~~ + + + + + + +### `_.intersection([array1, array2, ...])` +Computes the intersection of all the passed-in arrays. +[▲][1] + +#### Arguments +1. `[array1, array2, ...]` *(Mixed)*: Arrays to process. + +#### Returns +*(Array)*: Returns a new array of unique values, in order, that are present in **all** of the arrays. + +#### Example +~~~ js +_.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]); +// => [1, 2] +~~~ + + + + + + +### `_.invoke(collection, methodName [, arg1, arg2, ...])` +Calls the method named by `methodName` for each value of the `collection`. Additional arguments will be passed to each invoked method. +[▲][1] + +#### Arguments +1. `collection` *(Array|Object)*: The collection to iterate over. +2. `methodName` *(String)*: The name of the method to invoke. +3. `[arg1, arg2, ...]` *(Mixed)*: Arguments to invoke the method with. + +#### Returns +*(Array)*: Returns a new array of values returned from each invoked method. + +#### Example +~~~ js +_.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); +// => [[1, 5, 7], [1, 2, 3]] +~~~ + + + + + + +### `_.isArguments(value)` +Checks if a `value` is an `arguments` object. +[▲][1] + +#### Arguments +1. `value` *(Mixed)*: The value to check. + +#### Returns +*(Boolean)*: Returns `true` if the `value` is an `arguments` object, else `false`. + +#### Example +~~~ js +(function() { return _.isArguments(arguments); })(1, 2, 3); +// => true + +_.isArguments([1, 2, 3]); +// => false +~~~ + + + + + + +### `_.isArray(value)` +Checks if a `value` is an array. +[▲][1] + +#### Arguments +1. `value` *(Mixed)*: The value to check. + +#### Returns +*(Boolean)*: Returns `true` if the `value` is an array, else `false`. + +#### Example +~~~ js +(function() { return _.isArray(arguments); })(); +// => false + +_.isArray([1, 2, 3]); +// => true +~~~ + + + + + + +### `_.isBoolean(value)` +Checks if a `value` is a boolean *(`true` or `false`)* value. +[▲][1] + +#### Arguments +1. `value` *(Mixed)*: The value to check. + +#### Returns +*(Boolean)*: Returns `true` if the `value` is a boolean value, else `false`. + +#### Example +~~~ js +_.isBoolean(null); +// => false +~~~ + + + + + + +### `_.isDate(value)` +Checks if a `value` is a date. +[▲][1] + +#### Arguments +1. `value` *(Mixed)*: The value to check. + +#### Returns +*(Boolean)*: Returns `true` if the `value` is a date, else `false`. + +#### Example +~~~ js +_.isDate(new Date); +// => true +~~~ + + + + + + +### `_.isElement(value)` +Checks if a `value` is a DOM element. +[▲][1] + +#### Arguments +1. `value` *(Mixed)*: The value to check. + +#### Returns +*(Boolean)*: Returns `true` if the `value` is a DOM element, else `false`. + +#### Example +~~~ js +_.isElement(document.body); +// => true +~~~ + + + + + + +### `_.isEmpty(value)` +Checks if a `value` is empty. Arrays or strings with a length of `0` and objects with no enumerable own properties are considered "empty". +[▲][1] + +#### Arguments +1. `value` *(Mixed)*: The value to check. + +#### Returns +*(Boolean)*: Returns `true` if the `value` is empty, else `false`. + +#### Example +~~~ js +_.isEmpty([1, 2, 3]); +// => false + +_.isEmpty({}); +// => true +~~~ + + + + + + +### `_.isEqual(value, other)` +Performs a deep comparison between two values to determine if they are equivalent to each other. +[▲][1] + +#### Arguments +1. `value` *(Mixed)*: The value to compare. +2. `other` *(Mixed)*: The other value to compare. + +#### Returns +*(Boolean)*: Returns `true` if the values are equvalent, else `false`. + +#### Example +~~~ js +var moe = { 'name': 'moe', 'luckyNumbers': [13, 27, 34] }; +var clone = { 'name': 'moe', 'luckyNumbers': [13, 27, 34] }; + +moe == clone; +// => false + +_.isEqual(moe, clone); +// => true +~~~ + + + + + + +### `_.isFinite(value)` +Checks if a `value` is a finite number. +[▲][1] + +#### Arguments +1. `value` *(Mixed)*: The value to check. + +#### Returns +*(Boolean)*: Returns `true` if the `value` is a finite number, else `false`. + +#### Example +~~~ js +_.isFinite(-101); +// => true + +_.isFinite('10'); +// => false + +_.isFinite(Infinity); +// => false +~~~ + + + + + + +### `_.isFunction(value)` +Checks if a `value` is a function. +[▲][1] + +#### Arguments +1. `value` *(Mixed)*: The value to check. + +#### Returns +*(Boolean)*: Returns `true` if the `value` is a function, else `false`. + +#### Example +~~~ js +_.isFunction(''.concat); +// => true +~~~ + + + + + + +### `_.isNaN(value)` +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. +[▲][1] + +#### Arguments +1. `value` *(Mixed)*: The value to check. + +#### Returns +*(Boolean)*: Returns `true` if the `value` is `NaN`, else `false`. + +#### Example +~~~ js +_.isNaN(NaN); +// => true + +isNaN(undefined); +// => true + +_.isNaN(undefined); +// => false +~~~ + + + + + + +### `_.isNull(value)` +Checks if a `value` is `null`. +[▲][1] + +#### Arguments +1. `value` *(Mixed)*: The value to check. + +#### Returns +*(Boolean)*: Returns `true` if the `value` is `null`, else `false`. + +#### Example +~~~ js +_.isNull(null); +// => true + +_.isNull(undefined); +// => false +~~~ + + + + + + +### `_.isNumber(value)` +Checks if a `value` is a number. +[▲][1] + +#### Arguments +1. `value` *(Mixed)*: The value to check. + +#### Returns +*(Boolean)*: Returns `true` if the `value` is a number, else `false`. + +#### Example +~~~ js +_.isNumber(8.4 * 5; +// => true +~~~ + + + + + + +### `_.isObject(value)` +Checks if a `value` is an object. +[▲][1] + +#### Arguments +1. `value` *(Mixed)*: The value to check. + +#### Returns +*(Boolean)*: Returns `true` if the `value` is an object, else `false`. + +#### Example +~~~ js +_.isObject({}); +// => true + +_.isObject(1); +// => false +~~~ + + + + + + +### `_.isRegExp(value)` +Checks if a `value` is a regular expression. +[▲][1] + +#### Arguments +1. `value` *(Mixed)*: The value to check. + +#### Returns +*(Boolean)*: Returns `true` if the `value` is a regular expression, else `false`. + +#### Example +~~~ js +_.isRegExp(/moe/); +// => true +~~~ + + + + + + +### `_.isString(value)` +Checks if a `value` is a string. +[▲][1] + +#### Arguments +1. `value` *(Mixed)*: The value to check. + +#### Returns +*(Boolean)*: Returns `true` if the `value` is a string, else `false`. + +#### Example +~~~ js +_.isString('moe'); +// => true +~~~ + + + + + + +### `_.isUndefined(value)` +Checks if a `value` is `undefined`. +[▲][1] + +#### Arguments +1. `value` *(Mixed)*: The value to check. + +#### Returns +*(Boolean)*: Returns `true` if the `value` is `undefined`, else `false`. + +#### Example +~~~ js +_.isUndefined(void 0); +// => true +~~~ + + + + + + +### `_.keys(object)` +Produces an array of the `object`'s enumerable own property names. +[▲][1] + +#### Arguments +1. `object` *(Object)*: The object to inspect. + +#### Returns +*(Array)*: Returns a new array of property names. + +#### Example +~~~ js +_.keys({ 'one': 1, 'two': 2, 'three': 3 }); +// => ['one', 'two', 'three'] +~~~ + + + + + + +### `_.last(array [, n, guard])` +Gets the last value of the `array`. Pass `n` to return the lasy `n` values of the `array`. +[▲][1] + +#### Arguments +1. `array` *(Array)*: The array to query. +2. `[n]` *(Number)*: The number of elements to return. +3. `[guard]` *(Object)*: Used to allow the function to work with other iteration methods like `_.map` without using their callback `index` argument for `n`. + +#### Returns +*(Array)*: Returns all but the last value or `n` values of the `array`. + +#### Example +~~~ js +_.last([5, 4, 3, 2, 1]); +// => 1 +~~~ + + + + + + +### `_.lastIndexOf(array, value)` +Gets the index at which the last occurrence of `value` is found using strict equality for comparisons, i.e. `===`. +[▲][1] + +#### Arguments +1. `array` *(Array)*: The array to search. +2. `value` *(Mixed)*: The value to search for. + +#### Returns +*(Number)*: Returns the index of the matched value or `-1`. + +#### Example +~~~ js +_.lastIndexOf([1, 2, 3, 1, 2, 3], 2); +// => 4 +~~~ + + + + + + +### `_.map(collection, callback [, thisArg])` +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)*. +[▲][1] + +#### Arguments +1. `collection` *(Array|Object)*: The collection to iterate over. +2. `callback` *(Function)*: The function called per iteration. +3. `[thisArg]` *(Mixed)*: The `this` binding for the callback. + +#### Returns +*(Array)*: Returns a new array of values returned by the callback. + +#### Example +~~~ js +_.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] +~~~ + + + + + + +### `_.max(collection [, callback, thisArg])` +Retrieves the maximum value of a `collection`. If `callback` is passed, it will be executed for each value in the `collection` to generate the criterion by which the value is ranked. The `callback` is invoked with `3` arguments; for arrays they are *(value, index, array)* and for objects they are *(value, key, object)*. +[▲][1] + +#### Arguments +1. `collection` *(Array|Object)*: The collection to iterate over. +2. `[callback]` *(Function)*: The function called per iteration. +3. `[thisArg]` *(Mixed)*: The `this` binding for the callback. + +#### Returns +*(Mixed)*: Returns the maximum value. + +#### Example +~~~ js +var stooges = [ + { 'name' : 'moe', 'age' : 40}, + { 'name' : 'larry', 'age' : 50}, + { 'name' : 'curly', 'age' : 60} +]; + +_.max(stooges, function(stooge) { return stooge.age; }); +// => { 'name' : 'curly', 'age' : 60 }; +~~~ + + + + + + +### `_.memoize(func [, hasher=_.identity])` +Creates a new function that memoizes the result of `func`. If `hasher` is passed, it will be used to compute the hash key for storing the result, based on the arguments to the original function. The default `hasher` uses the first argument to the memoized function as the cache key. +[▲][1] + +#### Arguments +1. `func` *(Function)*: The function to memoize the output of. +2. `[hasher=_.identity]` *(Function)*: A function used to resolve the cache keyW. + +#### Returns +*(Function)*: Returns the new memoizing function. + +#### Example +~~~ js +var fibonacci = _.memoize(function(n) { + return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2); +}); +~~~ + + + + + + +### `_.min(collection [, callback, thisArg])` +Retrieves the minimum value of a `collection`. If `callback` is passed, it will be executed for each value in the `collection` to generate the criterion by which the value is ranked. The `callback` is invoked with `3` arguments; for arrays they are *(value, index, array)* and for objects they are *(value, key, object)*. +[▲][1] + +#### Arguments +1. `collection` *(Array|Object)*: The collection to iterate over. +2. `[callback]` *(Function)*: The function called per iteration. +3. `[thisArg]` *(Mixed)*: The `this` binding for the callback. + +#### Returns +*(Mixed)*: Returns the minimum value. + +#### Example +~~~ js +_.min([10, 5, 100, 2, 1000]); +// => 2 +~~~ + + + + + + +### `_.mixin(object)` +Adds functions properties of `object` to the `lodash` function and chainable wrapper. +[▲][1] + +#### Arguments +1. `object` *(Object)*: The object of function properties to add to `lodash`. + +#### Example +~~~ js +_.mixin({ + 'capitalize': function(string) { + return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase(); + } +}); + +_.capitalize('curly'); +// => 'Curly' + +_('larry').capitalize(); +// => 'Larry' +~~~ + + + + + + +### `_.noConflict()` +Reverts the '_' variable to its previous value and returns a reference to the `lodash` function. +[▲][1] + +#### Returns +*(Function)*: Returns the `lodash` function. + +#### Example +~~~ js +var lodash = _.noConflict(); +~~~ + + + + + + +### `_.once(func)` +Creates a new function that is restricted to one execution. Repeat calls to the function will return the value of the first call. +[▲][1] + +#### Arguments +1. `func` *(Function)*: The function to restrict. + +#### Returns +*(Function)*: Returns the new restricted function. + +#### Example +~~~ js +var initialize = _.once(createApplication); +initialize(); +initialize(); +// Application is only created once. +~~~ + + + + + + +### `_.pick(object [, prop1, prop2, ..])` +Creates an object composed of the specified properties. Property names may be specified as individual arguments or as arrays of property names. +[▲][1] + +#### Arguments +1. `object` *(Object)*: The object to pluck. +2. `[prop1, prop2, ..]` *(Object)*: The properties to pick. + +#### Returns +*(Object)*: Returns an object composed of the picked properties. + +#### Example +~~~ js +_.pick({ 'name': 'moe', 'age': 40, 'userid': 'moe1' }, 'name', 'age'); +// => { 'name': 'moe', 'age': 40 } +~~~ + + + + + + +### `_.pluck(collection, property)` +Retrieves the value of a specified property from all values in a `collection`. +[▲][1] + +#### Arguments +1. `collection` *(Array|Object)*: The collection to iterate over. +2. `property` *(String)*: The property to pluck. + +#### Returns +*(Array)*: Returns a new array of property values. + +#### Example +~~~ js +var stooges = [ + { 'name' : 'moe', 'age' : 40}, + { 'name' : 'larry', 'age' : 50}, + { 'name' : 'curly', 'age' : 60} +]; + +_.pluck(stooges, 'name'); +// => ['moe', 'larry', 'curly'] +~~~ + + + + + + +### `_.range([start=0], end [, step=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. +[▲][1] + +#### Arguments +1. `[start=0]` *(Number)*: The start of the range. +2. `end` *(Number)*: The end of the range. +3. `[step=1]` *(Number)*: The value to increment or descrement by. + +#### Returns +*(Array)*: Returns a new range array. + +#### Example +~~~ js +_.range(10); +// => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + +_.range(1, 11); +// => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + +_.range(0, 30, 5); +// => [0, 5, 10, 15, 20, 25] + +_.range(0, -10, -1); +// => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] + +_.range(0); +// => [] +~~~ + + + + + + +### `_.reduce(collection, callback [, accumulator, thisArg])` +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)*. +[▲][1] + +#### Arguments +1. `collection` *(Array|Object)*: The collection to iterate over. +2. `callback` *(Function)*: The function called per iteration. +3. `[accumulator]` *(Mixed)*: Initial value of the accumulator. +4. `[thisArg]` *(Mixed)*: The `this` binding for the callback. + +#### Returns +*(Mixed)*: Returns the accumulated value. + +#### Example +~~~ js +var sum = _.reduce([1, 2, 3], function(memo, num) { return memo + num; }); +// => 6 +~~~ + + + + + + +### `_.reduceRight(collection, callback [, accumulator, thisArg])` +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)*. +[▲][1] + +#### Arguments +1. `collection` *(Array|Object)*: The collection to iterate over. +2. `callback` *(Function)*: The function called per iteration. +3. `[accumulator]` *(Mixed)*: Initial value of the accumulator. +4. `[thisArg]` *(Mixed)*: The `this` binding for the callback. + +#### Returns +*(Mixed)*: Returns the accumulated value. + +#### Example +~~~ js +var list = [[0, 1], [2, 3], [4, 5]]; +var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []); +// => [4, 5, 2, 3, 0, 1] +~~~ + + + + + + +### `_.reject(collection, callback [, thisArg])` +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)*. +[▲][1] + +#### Arguments +1. `collection` *(Array|Object)*: The collection to iterate over. +2. `callback` *(Function)*: The function called per iteration. +3. `[thisArg]` *(Mixed)*: The `this` binding for the callback. + +#### Returns +*(Array)*: Returns a new array of values that did **not** pass the callback check. + +#### Example +~~~ js +var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); +// => [1, 3, 5] +~~~ + + + + + + +### `_.rest(array [, n, guard])` +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. +[▲][1] + +#### Arguments +1. `array` *(Array)*: The array to query. +2. `[n]` *(Number)*: The number of elements to return. +3. `[guard]` *(Object)*: Used to allow the function to work with other iteration methods like `_.map` without using their callback `index` argument for `n`. + +#### Returns +*(Array)*: Returns all but the first value or `n` values of the `array`. + +#### Example +~~~ js +_.rest([5, 4, 3, 2, 1]); +// => [4, 3, 2, 1] +~~~ + + + + + + +### `_.result(object, property)` +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. +[▲][1] + +#### Arguments +1. `object` *(Object)*: The object to inspect. +2. `property` *(String)*: The property to get the result of. + +#### Returns +*(Mixed)*: Returns the resolved. + +#### Example +~~~ js +var object = { + 'cheese': 'crumpets', + 'stuff': function() { + return 'nonsense'; + } +}; + +_.result(object, 'cheese'); +// => 'crumpets' + +_.result(object, 'stuff'); +// => 'nonsense' +~~~ + + + + + + +### `_.shuffle(collection)` +Produces a new array of shuffled `collection` values, using a version of the Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle. +[▲][1] + +#### Arguments +1. `collection` *(Array|Object)*: The collection to shuffle. + +#### Returns +*(Array)*: Returns a new shuffled array. + +#### Example +~~~ js +_.shuffle([1, 2, 3, 4, 5, 6]); +// => [4, 1, 6, 3, 5, 2] +~~~ + + + + + + +### `_.size(collection)` +Gets the number of values in the `collection`. +[▲][1] + +#### Arguments +1. `collection` *(Array|Object)*: The collection inspect. + +#### Returns +*(Number)*: Returns the number of values in the collection. + +#### Example +~~~ js +_.size({ 'one': 1, 'two': 2, 'three': 3 }); +// => 3 +~~~ + + + + + + +### `_.some(collection, callback [, thisArg])` +Checks if the `callback` returns truthy for **any** value 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)*. +[▲][1] + +#### Arguments +1. `collection` *(Array|Object)*: The collection to iterate over. +2. `callback` *(Function)*: The function called per iteration. +3. `[thisArg]` *(Mixed)*: The `this` binding for the callback. + +#### Returns +*(Boolean)*: Returns `true` if any value passes the callback check, else `false`. + +#### Example +~~~ js +_.some([null, 0, 'yes', false]); +// => true +~~~ + + + + + + +### `_.sortBy(collection, callback [, thisArg])` +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')*. +[▲][1] + +#### Arguments +1. `collection` *(Array|Object)*: The collection to iterate over. +2. `callback` *(Function|String)*: The function called per iteration or property name to sort by. +3. `[thisArg]` *(Mixed)*: The `this` binding for the callback. + +#### Returns +*(Array)*: Returns a new array of sorted values. + +#### Example +~~~ js +_.sortBy([1, 2, 3, 4, 5, 6], function(num) { return Math.sin(num); }); +// => [5, 4, 6, 3, 1, 2] +~~~ + + + + + + +### `_.sortedIndex(array, value [, callback])` +Uses a binary search to determine the index at which the `value` should be inserted into the `collection` in order to maintain the `collection`'s sorted order. 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` arguments. +[▲][1] + +#### Arguments +1. `array` *(Array)*: The array to iterate over. +2. `value` *(Mixed)*: The value to evaluate. +3. `[callback]` *(Function)*: The function called per iteration. + +#### Returns +*(Number)*: Returns the index at which the value should be inserted into the collection. + +#### Example +~~~ js +_.sortedIndex([10, 20, 30, 40, 50], 35); +// => 3 +~~~ + + + + + + +### `_.tap(value, interceptor)` +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. +[▲][1] + +#### Arguments +1. `value` *(Mixed)*: The value to pass to `callback`. +2. `interceptor` *(Function)*: The function to invoke. + +#### Returns +*(Mixed)*: Returns `value`. + +#### Example +~~~ js +_.chain([1,2,3,200]) + .filter(function(num) { return num % 2 == 0; }) + .tap(alert) + .map(function(num) { return num * num }) + .value(); +// => // [2, 200] (alerted) +// => [4, 40000] +~~~ + + + + + + +### `_.template(text, data, settings)` +JavaScript micro-templating, similar to John Resig's implementation. Lo-Dash templating handles arbitrary delimiters, preserves whitespace, and correctly escapes quotes within interpolated code. +[▲][1] + +#### Arguments +1. `text` *(String)*: The +2. `data` *(Obect)*: The +3. `settings` *(Object)*: + +#### Returns +*(String)*: Returns.... + +#### Example +~~~ js +var compiled = _.template('hello: <%= name %>'); +compiled({ 'name': 'moe' }); +// => 'hello: moe' + +var list = '% _.forEach(people, function(name) { %>
  • <%= name %>
  • <% }); %>'; +_.template(list, { 'people': ['moe', 'curly', 'larry'] }); +// => '
  • moe
  • curly
  • larry
  • ' + +var template = _.template('<%- value %>'); +template({ 'value': ' +~~~ + + + + + + +### `_.throttle(func, wait)` +Creates a new function that, when invoked, will only call the original function at most once per every `wait` milliseconds. +[▲][1] + +#### Arguments +1. `func` *(Function)*: The function to throttle. +2. `wait` *(Number)*: The number of milliseconds to throttle executions to. + +#### Returns +*(Function)*: Returns the new throttled function. + +#### Example +~~~ js +var throttled = _.throttle(updatePosition, 100); +jQuery(window).on('scroll', throttled); +~~~ + + + + + + +### `_.times(n, callback [, thisArg])` +Executes the `callback` function `n` times. +[▲][1] + +#### Arguments +1. `n` *(Number)*: The number of times to execute the callback. +2. `callback` *(Function)*: The function called per iteration. +3. `[thisArg]` *(Mixed)*: The `this` binding for the callback. + +#### Example +~~~ js +_.times(3, function() { genie.grantWish(); }); +~~~ + + + + + + +### `_.toArray(collection)` +Converts the `collection`, into an array. Useful for converting the `arguments` object. +[▲][1] + +#### Arguments +1. `collection` *(Array|Object)*: The collection to convert. + +#### Returns +*(Array)*: Returns the new converted array. + +#### Example +~~~ js +(function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4); +// => [2, 3, 4] +~~~ + + + + + + +### `_.union([array1, array2, ...])` +Computes the union of the passed-in arrays. +[▲][1] + +#### Arguments +1. `[array1, array2, ...]` *(Mixed)*: Arrays to process. + +#### Returns +*(Array)*: Returns a new array of unique values, in order, that are present in one or more of the arrays. + +#### Example +~~~ js +_.union([1, 2, 3], [101, 2, 1, 10], [2, 1]); +// => [1, 2, 3, 101, 10] +~~~ + + + + + + +### `_.uniq(array [, isSorted=false, callback])` +Produces a duplicate-value-free version of the `array` using strict equality for comparisons, i.e. `===`. If the `array` is already sorted, passing `true` for `isSorted` will run a faster algorithm. If `callback` is passed, each value of `array` is passed through a transformation `callback` before uniqueness is computed. The `callback` is invoked with `3` arguments; *(value, index, array)*. +[▲][1] + +#### Arguments +1. `array` *(Array)*: The array to process. +2. `[isSorted=false]` *(Boolean)*: A flag to indicate that the `array` is already sorted. +3. `[callback]` *(Function)*: A + +#### Returns +*(Array)*: Returns a duplicate-value-free array. + +#### Example +~~~ js +_.uniq([1, 2, 1, 3, 1, 4]); +// => [1, 2, 3, 4] +~~~ + + + + + + +### `_.uniqueId([prefix])` +Generates a unique id. If `prefix` is passed, the id will be appended to it. +[▲][1] + +#### Arguments +1. `[prefix]` *(String)*: The value to prefix the id with. + +#### Returns +*(Number, String)*: Returns a numeric id if no prefix is passed, else a string id may be returned. + +#### Example +~~~ js +_.uniqueId('contact_'); +// => 'contact_104' +~~~ + + + + + + +### `_.values(object)` +Produces an array of the `object`'s enumerable own property values. +[▲][1] + +#### Arguments +1. `object` *(Object)*: The object to inspect. + +#### Returns +*(Array)*: Returns a new array of property values. + +#### Example +~~~ js +_.values({ 'one': 1, 'two': 2, 'three': 3 }); +// => [1, 2, 3] +~~~ + + + + + + +### `_.without(array [, value1, value2, ...])` +Produces a new array with all occurrences of the values removed using strict equality for comparisons, i.e. `===`. +[▲][1] + +#### Arguments +1. `array` *(Array)*: The array to filter. +2. `[value1, value2, ...]` *(Mixed)*: Values to remove. + +#### Returns +*(Array)*: Returns a new filtered array. + +#### Example +~~~ js +_.without([1, 2, 1, 0, 3, 1, 4], 0, 1); +// => [2, 3, 4] +~~~ + + + + + + +### `_.wrap(func, wrapper [, arg1, arg2, ...])` +Create a new function that passes the `func` function to the `wrapper` function as its first argument. Additional arguments are appended to those passed to the `wrapper` function. +[▲][1] + +#### Arguments +1. `func` *(Function)*: The function to wrap. +2. `wrapper` *(Function)*: The wrapper function. +3. `[arg1, arg2, ...]` *(Mixed)*: Arguments to append to those passed to the wrapper. + +#### Returns +*(Function)*: Returns the new function. + +#### Example +~~~ js +var hello = function(name) { return 'hello: ' + name; }; +hello = _.wrap(hello, function(func) { + return 'before, ' + func('moe') + ', after'; +}); +hello(); +// => 'before, hello: moe, after' +~~~ + + + + + + +### `_.zip([array1, array2, ...])` +Merges together the values of each of the arrays with the value at the corresponding position. Useful for separate data sources that are coordinated through matching array indexes. For a matrix of nested arrays, `_.zip.apply(...)` can transpose the matrix in a similar fashion. +[▲][1] + +#### Arguments +1. `[array1, array2, ...]` *(Mixed)*: Arrays to process. + +#### Returns +*(Array)*: Returns a new array of merged arrays. + +#### Example +~~~ js +_.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]); +// => [['moe', 30, true], ['larry', 40, false], ['curly', 50, false]] +~~~ + + + + + + + + + +## `_.prototype` +### `_(value)` +The Lodash function. +[▲][1] + + + +### `_#chain()` +Extracts the value from a wrapped chainable object. +[▲][1] + +#### Returns +*(Mixed)*: Returns the wrapped object. + +#### Example +~~~ js +_([1, 2, 3]).value(); +// => [1, 2, 3] +~~~ + + + + + + +### `_#value()` +Extracts the value from a wrapped chainable object. +[▲][1] + +#### Returns +*(Mixed)*: Returns the wrapped object. + +#### Example +~~~ js +_([1, 2, 3]).value(); +// => [1, 2, 3] +~~~ + + + + + + + + + +## `_.templateSettings` + + + +### `_.templateSettings` +*(Object)*: By default, Lodash uses ERB-style template delimiters, change the following template settings to use alternative delimiters. +[▲][1] + + + + + + + + + + + [1]: #readme "Jump back to the TOC." \ No newline at end of file diff --git a/doc/parse.php b/doc/parse.php index b50de5796..658c1ffb2 100644 --- a/doc/parse.php +++ b/doc/parse.php @@ -1,7 +1,7 @@ '../' . $file, - 'title' => 'LowDash.js v0.1.0', - 'url' => 'https://github.com/bestiejs/lowdash/blob/master/lowdash.js' + 'title' => 'Lo-Dash v0.1.0', + 'url' => 'https://github.com/bestiejs/lodash/blob/master/lodash.js' )); // save to a .md file diff --git a/lodash.js b/lodash.js new file mode 100644 index 000000000..875d5ff74 --- /dev/null +++ b/lodash.js @@ -0,0 +1,2596 @@ +/*! + * Lo-Dash v0.1.0 + * Copyright 2012 John-David Dalton + * Based on Underscore.js 1.3.3, copyright 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. + * + * Available under MIT license + */ +;(function(window, undefined) { + 'use strict'; + + /** Used to assign each benchmark an incrimented id */ + var idCounter = 0; + + /** Detect free variable `exports` */ + var freeExports = typeof exports == 'object' && exports && + (typeof global == 'object' && global && global == global.global && (window = global), exports); + + // Establish the object that gets returned to break out of a loop iteration. + var breaker = {}; + + var oldDash = window._; + + // Save bytes in the minified (but not gzipped) version: + var ArrayProto = Array.prototype, + ObjProto = Object.prototype; + + // Create quick reference variables for speed access to core prototypes. + var concat = ArrayProto.concat, + hasOwnProperty = ObjProto.hasOwnProperty, + push = ArrayProto.push, + slice = ArrayProto.slice, + toString = ObjProto.toString, + unshift = ArrayProto.unshift; + + // All **ECMAScript 5** native function implementations that we hope to use + // are declared here. + var nativeIsArray = Array.isArray, + nativeIsFinite = window.isFinite, + nativeKeys = Object.keys; + + // When customizing `templateSettings`, if you don't want to define an + // interpolation, evaluation or escaping regex, we need one that is + // guaranteed not to match. + var noMatch = /.^/; + + // Certain characters need to be escaped so that they can be put into a + // string literal. + var escapes = { + '\\': '\\', + "'": "'", + 'r': '\r', + 'n': '\n', + 't': '\t', + 'u2028': '\u2028', + 'u2029': '\u2029' + }; + + for (var p in escapes) escapes[escapes[p]] = p; + var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; + var unescaper = /\\(\\|'|r|n|t|u2028|u2029)/g; + + // Within an interpolation, evaluation, or escaping, remove HTML escaping + // that had been previously added. + var unescape = function(code) { + return code.replace(unescaper, function(match, escape) { + return escapes[escape]; + }); + }; + + /*--------------------------------------------------------------------------*/ + + /** + * The Lodash function. + * + * @name _ + * @constructor + * @param {Mixed} value The value to wrap in a chainable `lowdash` object. + * @returns {Object} Returns a `lodash` instance. + * @example + */ + function lodash(value) { + // allow invoking `lodash` without the `new` operator + return new Wrapper(value); + } + + /** + * Creates a wrapped collection that can be used OO-style. This wrapper holds + * altered versions of all the Lo-Dash functions. Wrapped objects may be chained. + * + * @private + * @constructor + * @param {Mixed} value The value to wrap in a chainable `lodash` object. + * @example + */ + function Wrapper(collection) { + this._wrapped = collection; + } + + /*--------------------------------------------------------------------------*/ + + // Helper function to continue chaining intermediate results. + function resultWrapper(collection, chain) { + return chain ? lodash(collection).chain() : collection; + } + + // A method to easily add functions to the OOP wrapper. + function addToWrapper(name, func) { + Wrapper.prototype[name] = function() { + var args = slice.call(arguments); + unshift.call(args, this._wrapped); + return resultWrapper(func.apply(lodash, args), this._chain); + }; + } + + /** + * Internal recursive comparison function + * + * @private + * @param {Mixed} a A value. + * @param {Mixed} b Another value. + * @param {Array} stack Holds seen objects to avoid circular references. + * @example + */ + function eq(a, b, stack) { + // identical objects are equal. `0 === -0`, but they aren't identical + // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal + if (a === b) { + return a !== 0 || (1 / a == 1 / b); + } + // a strict comparison is necessary because `null == undefined` + if (a == null || b == null) { + return a === b; + } + // unwrap any wrapped objects + if (a._chain) { + a = a._wrapped; + } + if (b._chain) { + b = b._wrapped; + } + // invoke a custom `isEqual` method if one is provided + if (a.isEqual && isFunction(a.isEqual)) { + return a.isEqual(b); + } + if (b.isEqual && isFunction(b.isEqual)) { + return b.isEqual(a); + } + + // compare `[[Class]]` names + var className = toString.call(a); + if (className != toString.call(b)) { + return false; + } + switch (className) { + // strings, numbers, dates, and booleans are compared by value + case '[object String]': + // primitives and their corresponding collection wrappers are equivalent; thus, `"5"` is + // equivalent to `new String("5")` + return a == String(b); + + case '[object Number]': + // `NaN`s are equivalent, but non-reflexive; + // an `egal` comparison is performed for other numeric values + return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); + + case '[object Date]': + case '[object Boolean]': + // Coerce dates and booleans to numeric primitive values. + // Dates are compared by their millisecond representations. + // Note that invalid dates with millisecond representations of `NaN` are not equivalent. + return +a == +b; + + // regexps are compared by their source and flags + case '[object RegExp]': + return a.source == b.source && + a.global == b.global && + a.multiline == b.multiline && + a.ignoreCase == b.ignoreCase; + } + + if (typeof a != 'object' || typeof b != 'object') { + return false; + } + // Assume equality for cyclic structures. The algorithm for detecting cyclic + // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. + var length = stack.length; + while (length--) { + // Linear search. Performance is inversely proportional to the number of + // unique nested structures. + if (stack[length] == a) { + return true; + } + } + + // add the first collection to the stack of traversed objects + stack.push(a); + var size = 0, result = true; + + // recursively compare objects and arrays + if (className == '[object Array]') { + // compare array lengths to determine if a deep comparison is necessary + size = a.length; + result = size == b.length; + + if (result) { + // deep compare the contents, ignoring non-numeric properties + while (size--) { + // ensure commutative equality for sparse arrays + if (!(result = size in a == size in b && eq(a[size], b[size], stack))) { + break; + } + } + } + } else { + // objects with different constructors are not equivalent + if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) { + return false; + } + // deep compare objects + for (var key in a) { + if (hasOwnProperty.call(a, key)) { + // count the expected number of properties + size++; + // deep compare each member + if (!(result = hasOwnProperty.call(b, key) && eq(a[key], b[key], stack))) { + break; + } + } + } + // ensure that both objects contain the same number of properties + if (result) { + for (key in b) { + if (hasOwnProperty.call(b, key) && !(size--)) { + break; + } + } + result = !size; + } + } + // remove the first collection from the stack of traversed objects + stack.pop(); + return result; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Checks if a given `target` value is present in a `collection` using strict + * equality for comparisons, i.e. `===`. + * + * @static + * @memberOf _ + * @alias include + * @category Collections + * @param {Array|Object} collection The collection to iterate over. + * @param {Mixed} target The value to check for. + * @returns {Boolean} Returns `true` if `target` value is found, else `false`. + * @example + * + * _.contains([1, 2, 3], 3); + * // => true + */ + function contains(collection, target) { + return collection == null + ? false + : some(collection, function(value) { return value === target; }); + } + + /** + * Checks if the `callback` returns truthy for **all** values 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). + * + * @static + * @memberOf _ + * @alias all + * @category Collections + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} callback The function called per iteration. + * @param {Mixed} [thisArg] The `this` binding for the callback. + * @returns {Boolean} Returns `true` if all values pass the callback check, else `false`. + * @example + * + * _.every([true, 1, null, 'yes'], Boolean); + * => false + */ + function every(collection, callback, thisArg) { + var result = true; + if (collection == null) return result; + forEach(collection, function(value, index, array) { + if (!(result = result && callback.call(thisArg, value, index, array))) return breaker; + }); + return !!result; + } + + /** + * 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). + * + * @static + * @memberOf _ + * @alias select + * @category Collections + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} callback The function called per iteration. + * @param {Mixed} [thisArg] The `this` binding for the callback. + * @returns {Array} Returns a new array of values that passed callback check. + * @example + * + * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); + * // => [2, 4, 6] + */ + function filter(collection, callback, thisArg) { + var result = []; + if (collection == null) return result; + forEach(collection, function(value, index, array) { + if (callback.call(thisArg, value, index, array)) result[result.length] = value; + }); + return result; + } + + /** + * 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). + * + * @static + * @memberOf _ + * @alias detect + * @category Collections + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} callback The function called per iteration. + * @param {Mixed} [thisArg] The `this` binding for the callback. + * @returns {Mixed} Returns the value that passed the callback check. + * @example + * + * var even = _.find([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); + * // => 2 + */ + function find(collection, callback, thisArg) { + var result; + some(collection, function(value, index, array) { + if (callback.call(thisArg, value, index, array)) { + result = value; + return true; + } + }); + return result; + } + + /** + * 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). + * + * @static + * @memberOf _ + * @alias each + * @category Collections + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} callback The function called per iteration. + * @param {Mixed} [thisArg] The `this` binding for the callback. + * @returns {Array|Object} Returns the `collection`. + * @example + * + * _.forforEach([1, 2, 3], function(num) { alert(num); }); + * // => alerts each number in turn... + * + * _.forforEach({ 'one' : 1, 'two' : 2, 'three' : 3}, function(num) { alert(num); }); + * // => alerts each number in turn... + */ + function forEach(collection, callback, thisArg) { + if (collection != null) { + if (collection.length === +collection.length) { + for (var index = 0, length = collection.length; index < length; index++) { + if (index in collection && callback.call(thisArg, collection[index], index, collection) === breaker) { + break; + } + } + } else { + for (var key in collection) { + if (hasOwnProperty.call(collection, key)) { + if (callback.call(thisArg, collection[key], key, collection) === breaker) { + break; + } + } + } + } + } + return collection; + } + + /** + * Splits a `collection` into sets, grouped by the result of running each value + * 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 group by. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object} collection The collection to iterate over. + * @param {Function|String} callback The function called per iteration or + * property name to group by. + * @param {Mixed} [thisArg] The `this` binding for the callback. + * @returns {Object} Returns an object of grouped values. + * @example + * + * _.groupBy([1.3, 2.1, 2.4], function(num) { return Math.floor(num); }); + * // => { '1': [1.3], '2': [2.1, 2.4] } + * + * _.groupBy(['one', 'two', 'three'], 'length'); + * // => { '3': ['one', 'two'], '5': ['three'] } + */ + function groupBy(collection, callback, thisArg) { + var result = {}; + if (!isFunction(callback)) { + var key = callback; + callback = function(collection) { return collection[key]; }; + } + forEach(collection, function(value, index) { + var key = callback(value, index); + (result[key] || (result[key] = [])).push(value); + }); + return result; + } + + /** + * Calls the method named by `methodName` for each value of the `collection`. + * Additional arguments will be passed to each invoked method. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object} collection The collection to iterate over. + * @param {String} methodName The name of the method to invoke. + * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the method with. + * @returns {Array} Returns a new array of values returned from each invoked method. + * @example + * + * _.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); + * // => [[1, 5, 7], [1, 2, 3]] + */ + function invoke(collection, methodName) { + var args = slice.call(arguments, 2), + isFunc = isFunction(methodName); + + return map(collection, function(value) { + return (isFunc ? methodName || value : value[methodName]).apply(value, args); + }); + } + + /** + * 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). + * + * @static + * @memberOf _ + * @alias collect + * @category Collections + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} callback The function called per iteration. + * @param {Mixed} [thisArg] The `this` binding for the callback. + * @returns {Array} Returns a new array of values returned by the callback. + * @example + * + * _.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] + */ + function map(collection, callback, thisArg) { + var result = []; + if (collection == null) { + return result; + } + forEach(collection, function(value, index, array) { + result[result.length] = callback.call(thisArg, value, index, array); + }); + if (collection.length === +collection.length) result.length = collection.length; + return result; + } + + /** + * Retrieves the maximum value of a `collection`. If `callback` is passed, + * it will be executed for each value in the `collection` to generate the + * criterion by which the value is ranked. The `callback` is invoked with 3 + * arguments; for arrays they are (value, index, array) and for objects they + * are (value, key, object). + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [callback] The function called per iteration. + * @param {Mixed} [thisArg] The `this` binding for the callback. + * @returns {Mixed} Returns the maximum value. + * @example + * + * var stooges = [ + * { 'name' : 'moe', 'age' : 40}, + * { 'name' : 'larry', 'age' : 50}, + * { 'name' : 'curly', 'age' : 60} + * ]; + * + * _.max(stooges, function(stooge) { return stooge.age; }); + * // => { 'name' : 'curly', 'age' : 60 }; + */ + function max(collection, callback, thisArg) { + if (!callback && isArray(collection) && collection[0] === +collection[0]) + return Math.max.apply(Math, collection); + if (!callback && isEmpty(collection)) + return -Infinity; + var result = {computed : -Infinity}; + forEach(collection, function(value, index, array) { + var computed = callback ? callback.call(thisArg, value, index, array) : value; + computed >= result.computed && (result = { 'computed': computed, 'value': value }); + }); + return result.value; + } + + /** + * Retrieves the minimum value of a `collection`. If `callback` is passed, + * it will be executed for each value in the `collection` to generate the + * criterion by which the value is ranked. The `callback` is invoked with 3 + * arguments; for arrays they are (value, index, array) and for objects they + * are (value, key, object). + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [callback] The function called per iteration. + * @param {Mixed} [thisArg] The `this` binding for the callback. + * @returns {Mixed} Returns the minimum value. + * @example + * + * _.min([10, 5, 100, 2, 1000]); + * // => 2 + */ + function min(collection, callback, thisArg) { + if (!callback && isArray(collection) && collection[0] === +collection[0]) return Math.min.apply(Math, collection); + if (!callback && isEmpty(collection)) return Infinity; + var result = {computed : Infinity}; + forEach(collection, function(value, index, array) { + var computed = callback ? callback.call(thisArg, value, index, array) : value; + computed < result.computed && (result = { 'computed': computed, 'value': value }); + }); + return result.value; + } + + /** + * Retrieves the value of a specified property from all values in a `collection`. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object} collection The collection to iterate over. + * @param {String} property The property to pluck. + * @returns {Array} Returns a new array of property values. + * @example + * + * var stooges = [ + * { 'name' : 'moe', 'age' : 40}, + * { 'name' : 'larry', 'age' : 50}, + * { 'name' : 'curly', 'age' : 60} + * ]; + * + * _.pluck(stooges, 'name'); + * // => ['moe', 'larry', 'curly'] + */ + function pluck(collection, key) { + return map(collection, function(value){ return value[key]; }); + } + + /** + * 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). + * + * @static + * @memberOf _ + * @alias foldl, inject + * @category Collections + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} callback The function called per iteration. + * @param {Mixed} [accumulator] Initial value of the accumulator. + * @param {Mixed} [thisArg] The `this` binding for the callback. + * @returns {Mixed} Returns the accumulated value. + * @example + * + * var sum = _.reduce([1, 2, 3], function(memo, num) { return memo + num; }); + * // => 6 + */ + function reduce(collection, callback, accumulator, thisArg) { + var initial = arguments.length > 2; + if (collection == null) collection = []; + forEach(collection, function(value, index, array) { + if (!initial) { + accumulator = value; + initial = true; + } else { + accumulator = callback.call(thisArg, accumulator, value, index, array); + } + }); + if (!initial) throw new TypeError('Reduce of empty array with no initial value'); + return accumulator; + } + + /** + * 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). + * + * @static + * @memberOf _ + * @alias foldr + * @category Collections + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} callback The function called per iteration. + * @param {Mixed} [accumulator] Initial value of the accumulator. + * @param {Mixed} [thisArg] The `this` binding for the callback. + * @returns {Mixed} Returns the accumulated value. + * @example + * + * var list = [[0, 1], [2, 3], [4, 5]]; + * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []); + * // => [4, 5, 2, 3, 0, 1] + */ + function reduceRight(collection, callback, accumulator, thisArg) { + var initial = arguments.length > 2; + if (collection == null) collection = []; + var reversed = toArray(collection).reverse(); + if (thisArg && !initial) callback = bind(callback, thisArg); + return initial ? reduce(reversed, callback, accumulator, thisArg) : reduce(reversed, callback); + } + + /** + * 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). + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} callback The function called per iteration. + * @param {Mixed} [thisArg] The `this` binding for the callback. + * @returns {Array} Returns a new array of values that did **not** pass the callback check. + * @example + * + * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); + * // => [1, 3, 5] + */ + function reject(collection, callback, thisArg) { + var result = []; + if (collection == null) return result; + forEach(collection, function(value, index, array) { + if (!callback.call(thisArg, value, index, array)) result[result.length] = value; + }); + return result; + } + + /** + * Produces a new array of shuffled `collection` values, using a version of the + * Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object} collection The collection to shuffle. + * @returns {Array} Returns a new shuffled array. + * @example + * + * _.shuffle([1, 2, 3, 4, 5, 6]); + * // => [4, 1, 6, 3, 5, 2] + */ + function shuffle(collection) { + var shuffled = [], rand; + forEach(collection, function(value, index, array) { + rand = Math.floor(Math.random() * (index + 1)); + shuffled[index] = shuffled[rand]; + shuffled[rand] = value; + }); + return shuffled; + } + + /** + * Gets the number of values in the `collection`. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object} collection The collection inspect. + * @returns {Number} Returns the number of values in the collection. + * @example + * + * _.size({ 'one': 1, 'two': 2, 'three': 3 }); + * // => 3 + */ + function size(collection) { + return isArray(collection) ? collection.length : keys(collection).length; + } + + /** + * 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'). + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object} collection The collection to iterate over. + * @param {Function|String} callback The function called per iteration or + * property name to sort by. + * @param {Mixed} [thisArg] The `this` binding for the callback. + * @returns {Array} Returns a new array of sorted values. + * @example + * + * _.sortBy([1, 2, 3, 4, 5, 6], function(num) { return Math.sin(num); }); + * // => [5, 4, 6, 3, 1, 2] + */ + function sortBy(collection, callback, thisArg) { + if (!isFunction(callback)) { + var key = callback; + callback = function(collection) { return collection[key]; }; + } + return pluck(map(collection, function(value, index, array) { + return { + 'value' : value, + 'criteria' : callback.call(thisArg, value, index, array) + }; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + if (a === void 0) return 1; + if (b === void 0) return -1; + return a < b ? -1 : a > b ? 1 : 0; + }), 'value'); + } + + /** + * Checks if the `callback` returns truthy for **any** value 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). + * + * @static + * @memberOf _ + * @alias any + * @category Collections + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} callback The function called per iteration. + * @param {Mixed} [thisArg] The `this` binding for the callback. + * @returns {Boolean} Returns `true` if any value passes the callback check, else `false`. + * @example + * + * _.some([null, 0, 'yes', false]); + * // => true + */ + function some(collection, callback, thisArg) { + callback || (callback = identity); + var result = false; + if (collection == null) return result; + forEach(collection, function(value, index, array) { + if (result || (result = callback.call(thisArg, value, index, array))) return breaker; + }); + return !!result; + } + + /** + * Uses a binary search to determine the index at which the `value` should be + * inserted into the `collection` in order to maintain the `collection`'s sorted + * order. 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 arguments. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array} array The array to iterate over. + * @param {Mixed} value The value to evaluate. + * @param {Function} [callback] The function called per iteration. + * @returns {Number} Returns the index at which the value should be inserted + * into the collection. + * @example + * + * _.sortedIndex([10, 20, 30, 40, 50], 35); + * // => 3 + */ + function sortedIndex(array, object, callback) { + callback || (callback = identity); + var low = 0, high = array.length; + while (low < high) { + var mid = (low + high) >> 1; + callback(array[mid]) < callback(object) ? low = mid + 1 : high = mid; + } + return low; + } + + /** + * Converts the `collection`, into an array. Useful for converting the + * `arguments` object. + * + * @static + * @memberOf _ + * @category Collections + * @param {Array|Object} collection The collection to convert. + * @returns {Array} Returns the new converted array. + * @example + * + * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4); + * // => [2, 3, 4] + */ + function toArray(collection) { + if (!collection) { + return []; + } + if (isArray(collection) || isArguments(collection)) { + return slice.call(collection); + } + if (isFunction(collection.toArray)) { + return collection.toArray(); + } + return values(collection); + } + + /*--------------------------------------------------------------------------*/ + + /** + * Produces a new array with all falsey values of `array` removed. The values + * `false`, `null`, `0`, `""`, `undefined` and `NaN` are all falsey. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to compact. + * @returns {Array} Returns a new filtered array. + * @example + * + * _.compact([0, 1, false, 2, '', 3]); + * // => [1, 2, 3] + */ + function compact(array) { + return filter(array, Boolean); + } + + /** + * Produces a new array of `array` values not present in the other arrays + * using strict equality for comparisons, i.e. `===`. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to process. + * @param {Mixed} [array1, array2, ...] Arrays to check. + * @returns {Array} Returns a new array of `array` values not present in the + * other arrays. + * @example + * + * _.difference([1, 2, 3, 4, 5], [5, 2, 10]); + * // => [1, 3, 4] + */ + function difference(array) { + var values = concat.apply([], slice.call(arguments, 1)); + return filter(array, function(value) { return indexOf(values, value) < 0; }); + } + + /** + * Gets the first value of the `array`. Pass `n` to return the first `n` values + * of the `array`. + * + * @static + * @memberOf _ + * @alias head, take + * @category Arrays + * @param {Array} array The array to query. + * @param {Number} [n] The number of elements to return. + * @param {Object} [guard] Used to allow the function to work with other iteration + * methods like `_.map` without using their callback `index` argument for `n`. + * @returns {Mixed} Returns the first value or an array of the first `n` + * values of the `array`. + * @example + * + * _.first([5, 4, 3, 2, 1]); + * // => 5 + */ + function first(array, n, guard) { + return (n == null || guard) ? array[0] : slice.call(array, 0, n); + } + + /** + * Flattens a nested array (the nesting can be to any depth). If `shallow` is + * truthy, `array` will only be flattened a single level. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to compact. + * @param {Boolean} shallow A flag to indicate only flattening a single level. + * @returns {Array} Returns a new flattened array. + * @example + * + * _.flatten([1, [2], [3, [[4]]]]); + * // => [1, 2, 3, 4]; + * + * _.flatten([1, [2], [3, [[4]]]], true); + * // => [1, 2, 3, [[4]]]; + */ + function flatten(array, shallow) { + if (shallow) { + return concat.apply([], array); + } + return reduce(array, function(accumulator, value) { + if (isArray(value)) { + push.apply(accumulator, flatten(value)); + return accumulator; + } + accumulator[accumulator.length] = value; + return accumulator; + }, []); + } + + /** + * 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. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to search. + * @param {Mixed} value The value to search for. + * @param {Boolean} [isSorted=false] A flag to indicate that the `array` is already sorted. + * @returns {Number} Returns the index of the matched value or `-1`. + * @example + * + * _.indexOf([1, 2, 3], 2); + * // => 1 + */ + function indexOf(array, value, isSorted) { + var index, length; + if (array == null) { + return -1; + } + if (isSorted) { + index = sortedIndex(array, value); + return array[index] === value ? index : -1; + } + for (index = 0, length = array.length; index < length; index++) { + if (array[index] === value) { + return index; + } + } + return -1; + } + + /** + * Gets all but the last value of the `array`. Pass `n` to exclude the last `n` + * values from the result. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to query. + * @param {Number} [n] The number of elements to return. + * @param {Object} [guard] Used to allow the function to work with other iteration + * methods like `_.map` without using their callback `index` argument for `n`. + * @returns {Array} Returns all but the last value or `n` values of the `array`. + * @example + * + * _.initial([5, 4, 3, 2, 1]); + * // => [5, 4, 3, 2] + */ + function initial(array, n, guard) { + return slice.call(array, 0, -((n == null || guard) ? 1 : n)); + } + + /** + * Computes the intersection of all the passed-in arrays. + * + * @static + * @memberOf _ + * @alias intersect + * @category Arrays + * @param {Mixed} [array1, array2, ...] Arrays to process. + * @returns {Array} Returns a new array of unique values, in order, that are + * present in **all** of the arrays. + * @example + * + * _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]); + * // => [1, 2] + */ + function intersection(array) { + var rest = slice.call(arguments, 1); + return filter(uniq(array), function(value) { + return every(rest, function(other) { + return indexOf(other, value) >= 0; + }); + }); + } + + /** + * Gets the last value of the `array`. Pass `n` to return the lasy `n` values + * of the `array`. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to query. + * @param {Number} [n] The number of elements to return. + * @param {Object} [guard] Used to allow the function to work with other iteration + * methods like `_.map` without using their callback `index` argument for `n`. + * @returns {Array} Returns all but the last value or `n` values of the `array`. + * @example + * + * _.last([5, 4, 3, 2, 1]); + * // => 1 + */ + function last(array, n, guard) { + var length = array.length; + return (n == null || guard) ? array[length - 1] : slice.call(array, -n || length); + } + + /** + * Gets the index at which the last occurrence of `value` is found using + * strict equality for comparisons, i.e. `===`. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to search. + * @param {Mixed} value The value to search for. + * @returns {Number} Returns the index of the matched value or `-1`. + * @example + * + * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2); + * // => 4 + */ + function lastIndexOf(array, value) { + if (array != null) { + var index = array.length; + while (index--) { + if (array[index] === value) return index; + } + } + return -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. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Number} [start=0] The start of the range. + * @param {Number} end The end of the range. + * @param {Number} [step=1] The value to increment or descrement by. + * @returns {Array} Returns a new range array. + * @example + * + * _.range(10); + * // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + * + * _.range(1, 11); + * // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + * + * _.range(0, 30, 5); + * // => [0, 5, 10, 15, 20, 25] + * + * _.range(0, -10, -1); + * // => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] + * + * _.range(0); + * // => [] + */ + function range(start, end, step) { + if (arguments.length <= 1) { + end = start || 0; + start = 0; + } + step = arguments[2] || 1; + + var length = Math.max(Math.ceil((end - start) / step), 0); + var idx = 0; + var result = new Array(length); + + while(idx < length) { + result[idx++] = start; + start += step; + } + return result; + } + + /** + * 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. + * + * @static + * @memberOf _ + * @alias tail + * @category Arrays + * @param {Array} array The array to query. + * @param {Number} [n] The number of elements to return. + * @param {Object} [guard] Used to allow the function to work with other iteration + * methods like `_.map` without using their callback `index` argument for `n`. + * @returns {Array} Returns all but the first value or `n` values of the `array`. + * @example + * + * _.rest([5, 4, 3, 2, 1]); + * // => [4, 3, 2, 1] + */ + function rest(array, index, guard) { + return slice.call(array, (index == null || guard) ? 1 : index); + } + + /** + * Computes the union of the passed-in arrays. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Mixed} [array1, array2, ...] Arrays to process. + * @returns {Array} Returns a new array of unique values, in order, that are + * present in one or more of the arrays. + * @example + * + * _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]); + * // => [1, 2, 3, 101, 10] + */ + function union() { + return uniq(flatten(arguments, true)); + } + + /** + * Produces a duplicate-value-free version of the `array` using strict equality + * for comparisons, i.e. `===`. If the `array` is already sorted, passing `true` + * for `isSorted` will run a faster algorithm. If `callback` is passed, + * each value of `array` is passed through a transformation `callback` before + * uniqueness is computed. The `callback` is invoked with 3 arguments; + * (value, index, array). + * + * @static + * @memberOf _ + * @alias unique + * @category Arrays + * @param {Array} array The array to process. + * @param {Boolean} [isSorted=false] A flag to indicate that the `array` is already sorted. + * @param {Function} [callback] A + * @returns {Array} Returns a duplicate-value-free array. + * @example + * + * _.uniq([1, 2, 1, 3, 1, 4]); + * // => [1, 2, 3, 4] + */ + function uniq(array, isSorted, callback) { + var initial = callback ? map(array, callback) : array, + result = []; + + // the `isSorted` flag is irrelevant if the array only contains two elements. + if (array.length < 3) { + isSorted = true; + } + reduce(initial, function(accumulator, value, index) { + if (isSorted ? last(accumulator) !== value || !accumulator.length : indexOf(accumulator, value) < 0) { + accumulator.push(value); + result.push(array[index]); + } + return accumulator; + }, []); + return result; + } + + /** + * Produces a new array with all occurrences of the values removed using strict + * equality for comparisons, i.e. `===`. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Array} array The array to filter. + * @param {Mixed} [value1, value2, ...] Values to remove. + * @returns {Array} Returns a new filtered array. + * @example + * + * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1); + * // => [2, 3, 4] + */ + function without(array) { + return difference(array, slice.call(arguments, 1)); + } + + /** + * Merges together the values of each of the arrays with the value at the + * corresponding position. Useful for separate data sources that are coordinated + * through matching array indexes. For a matrix of nested arrays, `_.zip.apply(...)` + * can transpose the matrix in a similar fashion. + * + * @static + * @memberOf _ + * @category Arrays + * @param {Mixed} [array1, array2, ...] Arrays to process. + * @returns {Array} Returns a new array of merged arrays. + * @example + * + * _.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]); + * // => [['moe', 30, true], ['larry', 40, false], ['curly', 50, false]] + */ + function zip() { + var length = max(pluck(arguments, 'length')), + result = Array(length); + + for (var index = 0; index < length; index++) { + result[index] = pluck(arguments, index); + } + return result; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Creates a new function that is restricted to executing only after it is + * called a given number of `times`. + * + * @static + * @memberOf _ + * @category Functions + * @param {Number} times The number of times the function must be called before + * it is executed. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var renderNotes = _.after(notes.length, render); + * _.forEach(notes, function(note) { + * note.asyncSave({ 'success': renderNotes }); + * }); + * // renderNotes is run once, after all notes have saved. + */ + function after(times, func) { + if (times < 1) { + return func(); + } + return function() { + if (--times < 1) { + return func.apply(this, arguments); + } + }; + } + + /** + * Creates a new function that, when called, invokes `func` with the `this` + * binding of `thisArg` and prepends additional arguments to those passed to + * the bound function. + * + * @static + * @memberOf _ + * @category Functions + * @param {Function} func The function to bind. + * @param @param {Mixed} [thisArg] The `this` binding of `func`. + * @param {Mixed} [arg1, arg2, ...] Arguments to prepend to those passed to the bound function. + * @returns {Function} Returns the new bound function. + * @example + * + * var func = function(greeting){ return greeting + ': ' + this.name; }; + * func = _.bind(func, { 'name': 'moe' }, 'hi'); + * func(); + * // => 'hi: moe' + */ + function bind(func, thisArg) { + var args = args = slice.call(arguments, 2), + argsLength = args.length; + + return function() { + args.length = argsLength; + push.apply(args, arguments); + return func.apply(thisArg, args); + }; + } + + /** + * 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. + * + * @static + * @memberOf _ + * @category Functions + * @param {Object} object The object to bind and assign the bound methods to. + * @param {Mixed} [methodName1, methodName2, ...] Method names on the object to bind. + * @returns {Object} Returns the `object`. + * @example + * + * var buttonView = { + * 'label': 'lodash', + * 'onClick': function() { alert('clicked: ' + this.label); }, + * 'onHover': function() { console.log('hovering: ' + this.label); } + * }; + * + * _.bindAll(buttonView); + * jQuery('#lodash_button').on('click', buttonView.onClick); + * // => When the button is clicked, `this.label` will have the correct value + */ + function bindAll(object) { + var funcs = slice.call(arguments, 1); + if (funcs.length == 0) funcs = functions(object); + forEach(funcs, function(f) { object[f] = bind(object[f], object); }); + return object; + } + + /** + * 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()))`. + * + * @static + * @memberOf _ + * @category Functions + * @param {Mixed} [func1, func2, ...] Functions to compose. + * @returns {Function} Returns the new composed function. + * @example + * + * var greet = function(name) { return 'hi: ' + name; }; + * var exclaim = function(statement) { return statement + '!'; }; + * var welcome = _.compose(exclaim, greet); + * welcome('moe'); + * // => 'hi: moe!' + */ + function compose() { + var funcs = arguments; + return function() { + var args = arguments; + for (var index = funcs.length - 1; index >= 0; index--) { + args = [funcs[index].apply(this, args)]; + } + return args[0]; + }; + } + + /** + * Creates a new function that will postpone its execution until after `wait` + * milliseconds have elapsed since the last time it was invoked. Pass `true` + * for `immediate` to cause debounce to invoke the function on the leading, + * intead of the trailing, edge of the wait timeout. + * + * @static + * @memberOf _ + * @category Functions + * @param {Function} func The function to debounce. + * @param {Number} wait The number of milliseconds to postone. + * @param {Boolean} immediate A flag to indicate execution is on the leading + * edge of the wait timeout. + * @returns {Function} Returns the new debounced function. + * @example + * + * var lazyLayout = _.debounce(calculateLayout, 300); + * jQuery(window).on('resize', lazyLayout); + */ + function debounce(func, wait, immediate) { + var timeout; + return function() { + var thisArg = this, args = arguments; + var later = function() { + timeout = null; + if (!immediate) func.apply(thisArg, args); + }; + if (immediate && !timeout) func.apply(thisArg, args); + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + } + + /** + * Invokes the `func` function after `wait` milliseconds. Additional arguments + * are passed `func` when it is invoked. + * + * @static + * @memberOf _ + * @category Functions + * @param {Function} func The function to delay. + * @param {Number} wait The number of milliseconds to delay execution. + * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with. + * @returns {Number} Returns the `setTimeout` timeout id. + * @example + * + * var log = _.bind(console.log, console); + * _.delay(log, 1000, 'logged later'); + * // => 'logged later' (Appears after one second.) + */ + function delay(func, wait) { + var args = slice.call(arguments, 2); + return setTimeout(function(){ return func.apply(null, args); }, wait); + } + + /** + * Defers invoking the `func` function until the current call stack has cleared. + * Additional arguments are passed to `func` when it is invoked. + * + * @static + * @memberOf _ + * @category Functions + * @param {Function} func The function to defer. + * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with. + * @returns {Number} Returns the `setTimeout` timeout id. + * @example + * + * _.defer(function(){ alert('deferred'); }); + * // Returns from the function before the alert runs. + */ + function defer(func) { + var args = [func, 1]; + push.apply(args, slice.call(arguments, 1)); + return delay.apply(lodash, args); + } + + /** + * Creates a new function that memoizes the result of `func`. If `hasher` is + * passed, it will be used to compute the hash key for storing the result, + * based on the arguments to the original function. The default `hasher` uses + * the first argument to the memoized function as the cache key. + * + * @static + * @memberOf _ + * @category Functions + * @param {Function} func The function to memoize the output of. + * @param {Function} [hasher=_.identity] A function used to resolve the cache keyW. + * @returns {Function} Returns the new memoizing function. + * @example + * + * var fibonacci = _.memoize(function(n) { + * return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2); + * }); + */ + function memoize(func, hasher) { + var cache = {}; + hasher || (hasher = identity); + return function() { + var key = hasher.apply(this, arguments); + return hasOwnProperty.call(cache, key) ? cache[key] : (cache[key] = func.apply(this, arguments)); + }; + } + + /** + * Creates a new function that is restricted to one execution. Repeat calls to + * the function will return the value of the first call. + * + * @static + * @memberOf _ + * @category Functions + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var initialize = _.once(createApplication); + * initialize(); + * initialize(); + * // Application is only created once. + */ + function once(func) { + var result, + ran = false; + + return function() { + if (ran) { + return result; + } + ran = true; + return (result = func.apply(this, arguments)); + }; + } + + /** + * Creates a new function that, when invoked, will only call the original + * function at most once per every `wait` milliseconds. + * + * @static + * @memberOf _ + * @category Functions + * @param {Function} func The function to throttle. + * @param {Number} wait The number of milliseconds to throttle executions to. + * @returns {Function} Returns the new throttled function. + * @example + * + * var throttled = _.throttle(updatePosition, 100); + * jQuery(window).on('scroll', throttled); + */ + function throttle(func, wait) { + var thisArg, args, timeout, throttling, more, result; + var whenDone = debounce(function(){ more = throttling = false; }, wait); + return function() { + thisArg = this; args = arguments; + var later = function() { + timeout = null; + if (more) func.apply(thisArg, args); + whenDone(); + }; + if (!timeout) timeout = setTimeout(later, wait); + if (throttling) { + more = true; + } else { + result = func.apply(thisArg, args); + } + whenDone(); + throttling = true; + return result; + }; + } + + /** + * Create a new function that passes the `func` function to the `wrapper` + * function as its first argument. Additional arguments are appended to those + * passed to the `wrapper` function. + * + * @static + * @memberOf _ + * @category Functions + * @param {Function} func The function to wrap. + * @param {Function} wrapper The wrapper function. + * @param {Mixed} [arg1, arg2, ...] Arguments to append to those passed to the wrapper. + * @returns {Function} Returns the new function. + * @example + * + * var hello = function(name) { return 'hello: ' + name; }; + * hello = _.wrap(hello, function(func) { + * return 'before, ' + func('moe') + ', after'; + * }); + * hello(); + * // => 'before, hello: moe, after' + */ + function wrap(func, wrapper) { + return function() { + var args = [func]; + push.apply(args, arguments); + return wrapper.apply(this, args); + }; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Create a shallow clone of the `value`. Any nested objects or arrays will be + * assigned by reference and not cloned. + * + * @static + * @memberOf _ + * @category Objects + * @param {Mixed} value The value to clone. + * @returns {Mixed} Returns the cloned `value`. + * @example + * + * _.clone({ 'name': 'moe' }); + * // => { 'name': 'moe' }; + */ + function clone(value) { + if (!isObject(value)) { + return value; + } + return isArray(value) ? value.slice() : extend({}, value); + } + + /** + * 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. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The object to populate. + * @param {Object} [defaults1, defaults2, ..] The defaults objects to apply to `object`. + * @returns {Object} Returns `object`. + * @example + * + * var iceCream = { 'flavor': 'chocolate' }; + * _.defaults(iceCream, { 'flavor': 'vanilla', 'sprinkles': 'lots' }); + * // => { 'flavor': 'chocolate', 'sprinkles': 'lots' } + */ + function defaults(object) { + forEach(slice.call(arguments, 1), function(source) { + for (var prop in source) { + if (object[prop] == null) object[prop] = source[prop]; + } + }); + return object; + } + + /** + * Copies enumerable properties from the source objects to the `destination` object. + * Subsequent sources will overwrite propery assignments of previous sources. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} destination The destination object. + * @param {Object} [source1, source2, ..] The source objects. + * @returns {Object} Returns the `destination` object. + * @example + * + * _.extend({ 'name': 'moe' }, { 'age': 40 }); + * // => { 'name': 'moe', 'age': 40 } + */ + function extend(destination) { + forEach(slice.call(arguments, 1), function(source) { + for (var prop in source) { + destination[prop] = source[prop]; + } + }); + return destination; + } + + /** + * Produces a sorted array of the `object`'s enumerable own property names that + * have function values. + * + * @static + * @memberOf _ + * @alias methods + * @category Objects + * @param {Object} object The object to inspect. + * @returns {Array} Returns a new array of property names that have function values. + * @example + * + * _.functions(_); + * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...] + */ + function functions(object) { + var names = []; + for (var key in object) { + if (isFunction(object[key])) names.push(key); + } + return names.sort(); + } + + /** + * Checks if an object has the specified key as a direct property. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The object to check. + * @param {String} key The key to check for. + * @returns {Boolean} Returns `true` if key is a direct property, else `false`. + * @example + * + * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b'); + * // => true + */ + function has(object, key) { + return hasOwnProperty.call(object, key); + } + + /** + * Checks if a `value` is an `arguments` object. + * + * @static + * @memberOf _ + * @category Objects + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the `value` is an `arguments` object, else `false`. + * @example + * + * (function() { return _.isArguments(arguments); })(1, 2, 3); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ + function isArguments(value) { + return toString.call(value) == '[object Arguments]'; + } + + /** + * Checks if a `value` is an array. + * + * @static + * @memberOf _ + * @category Objects + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the `value` is an array, else `false`. + * @example + * + * (function() { return _.isArray(arguments); })(); + * // => false + * + * _.isArray([1, 2, 3]); + * // => true + */ + function isArray(value) { + return toString.call(value) == '[object Array]'; + } + + /** + * Checks if a `value` is a boolean (`true` or `false`) value. + * + * @static + * @memberOf _ + * @category Objects + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the `value` is a boolean value, else `false`. + * @example + * + * _.isBoolean(null); + * // => false + */ + function isBoolean(value) { + return value === true || value === false || toString.call(value) == '[object Boolean]'; + } + + /** + * Checks if a `value` is a date. + * + * @static + * @memberOf _ + * @category Objects + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the `value` is a date, else `false`. + * @example + * + * _.isDate(new Date); + * // => true + */ + function isDate(value) { + return toString.call(value) == '[object Date]'; + } + + /** + * Checks if a `value` is a DOM element. + * + * @static + * @memberOf _ + * @category Objects + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the `value` is a DOM element, else `false`. + * @example + * + * _.isElement(document.body); + * // => true + */ + function isElement(value) { + return !!(value && value.nodeType == 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". + * + * @static + * @memberOf _ + * @category Objects + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the `value` is empty, else `false`. + * @example + * + * _.isEmpty([1, 2, 3]); + * // => false + * + * _.isEmpty({}); + * // => true + */ + function isEmpty(value) { + if (value == null) { + return true; + } + if (isArray(value) || isString(value)) { + return value.length === 0; + } + for (var key in value) { + if (hasOwnProperty.call(value, key)) { + return false; + } + } + return true; + } + + /** + * Performs a deep comparison between two values to determine if they are + * equivalent to each other. + * + * @static + * @memberOf _ + * @category Objects + * @param {Mixed} value The value to compare. + * @param {Mixed} other The other value to compare. + * @returns {Boolean} Returns `true` if the values are equvalent, else `false`. + * @example + * + * var moe = { 'name': 'moe', 'luckyNumbers': [13, 27, 34] }; + * var clone = { 'name': 'moe', 'luckyNumbers': [13, 27, 34] }; + * + * moe == clone; + * // => false + * + * _.isEqual(moe, clone); + * // => true + */ + function isEqual(value, other) { + return eq(value, other, []); + } + + /** + * Checks if a `value` is a finite number. + * + * @static + * @memberOf _ + * @category Objects + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the `value` is a finite number, else `false`. + * @example + * + * _.isFinite(-101); + * // => true + * + * _.isFinite('10'); + * // => false + * + * _.isFinite(Infinity); + * // => false + */ + function isFinite(value) { + return isNumber(value) && nativeIsFinite(value); + } + + /** + * Checks if a `value` is a function. + * + * @static + * @memberOf _ + * @category Objects + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the `value` is a function, else `false`. + * @example + * + * _.isFunction(''.concat); + * // => true + */ + function isFunction(value) { + return toString.call(value) == '[object Function]'; + } + + /** + * Checks if a `value` is an object. + * + * @static + * @memberOf _ + * @category Objects + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject(1); + * // => false + */ + function isObject(value) { + return value === Object(value); + } + + /** + * 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. + * + * @static + * @memberOf _ + * @category Objects + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the `value` is `NaN`, else `false`. + * @example + * + * _.isNaN(NaN); + * // => true + * + * isNaN(undefined); + * // => true + * + * _.isNaN(undefined); + * // => false + */ + function isNaN(value) { + // `NaN` is the only value for which `===` is not reflexive. + return value !== value; + } + + /** + * Checks if a `value` is `null`. + * + * @static + * @memberOf _ + * @category Objects + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the `value` is `null`, else `false`. + * @example + * + * _.isNull(null); + * // => true + * + * _.isNull(undefined); + * // => false + */ + function isNull(value) { + return value === null; + } + + /** + * Checks if a `value` is a number. + * + * @static + * @memberOf _ + * @category Objects + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the `value` is a number, else `false`. + * @example + * + * _.isNumber(8.4 * 5; + * // => true + */ + function isNumber(value) { + return toString.call(value) == '[object Number]'; + } + + /** + * Checks if a `value` is a regular expression. + * + * @static + * @memberOf _ + * @category Objects + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the `value` is a regular expression, else `false`. + * @example + * + * _.isRegExp(/moe/); + * // => true + */ + function isRegExp(value) { + return toString.call(value) == '[object RegExp]'; + } + + /** + * Checks if a `value` is a string. + * + * @static + * @memberOf _ + * @category Objects + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the `value` is a string, else `false`. + * @example + * + * _.isString('moe'); + * // => true + */ + function isString(value) { + return toString.call(value) == '[object String]'; + } + + /** + * Checks if a `value` is `undefined`. + * + * @static + * @memberOf _ + * @category Objects + * @param {Mixed} value The value to check. + * @returns {Boolean} Returns `true` if the `value` is `undefined`, else `false`. + * @example + * + * _.isUndefined(void 0); + * // => true + */ + function isUndefined(value) { + return value === void 0; + } + + /** + * Produces an array of the `object`'s enumerable own property names. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The object to inspect. + * @returns {Array} Returns a new array of property names. + * @example + * + * _.keys({ 'one': 1, 'two': 2, 'three': 3 }); + * // => ['one', 'two', 'three'] + */ + function keys(object) { + if (object !== Object(object)) { + throw TypeError(); + } + var result = []; + for (var key in object) { + if (hasOwnProperty.call(object, key)) { + result[result.length] = key; + } + } + return result; + } + + /** + * Creates an object composed of the specified properties. Property names may + * be specified as individual arguments or as arrays of property names. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The object to pluck. + * @param {Object} [prop1, prop2, ..] The properties to pick. + * @returns {Object} Returns an object composed of the picked properties. + * @example + * + * _.pick({ 'name': 'moe', 'age': 40, 'userid': 'moe1' }, 'name', 'age'); + * // => { 'name': 'moe', 'age': 40 } + */ + function pick(object) { + var result = {}; + forEach(flatten(slice.call(arguments, 1)), function(key) { + if (key in object) result[key] = object[key]; + }); + return result; + } + + /** + * 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. + * + * @static + * @memberOf _ + * @category Objects + * @param {Mixed} value The value to pass to `callback`. + * @param {Function} interceptor The function to invoke. + * @returns {Mixed} Returns `value`. + * @example + * + * _.chain([1,2,3,200]) + * .filter(function(num) { return num % 2 == 0; }) + * .tap(alert) + * .map(function(num) { return num * num }) + * .value(); + * // => // [2, 200] (alerted) + * // => [4, 40000] + */ + function tap(value, interceptor) { + interceptor(value); + return value; + } + + /** + * Produces an array of the `object`'s enumerable own property values. + * + * @static + * @memberOf _ + * @alias methods + * @category Objects + * @param {Object} object The object to inspect. + * @returns {Array} Returns a new array of property values. + * @example + * + * _.values({ 'one': 1, 'two': 2, 'three': 3 }); + * // => [1, 2, 3] + */ + function values(object) { + return map(object, identity); + } + + /*--------------------------------------------------------------------------*/ + + /** + * Escapes a string for insertion into HTML, replacing `&`, `<`, `>`, `"`, `'`, + * and `/` characters. + * + * @static + * @memberOf _ + * @category Utilities + * @param {String} string The string to escape. + * @returns {String} Returns the escaped string. + * @example + * + * _.escape('Curly, Larry & Moe'); + * // => "Curly, Larry & Moe" + */ + function escape(string) { + return (string + '').replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"') + .replace(/'/g, ''').replace(/\//g,'/'); + } + + /** + * This function simply returns the first argument passed to it. + * Note: It is used throughout Lodash as a default callback. + * + * @static + * @memberOf _ + * @category Utilities + * @param {Mixed} value Any value. + * @returns {Mixed} Returns `value`. + * @example + * + * var moe = { 'name': 'moe' }; + * moe === _.identity(moe); + * // => true + */ + function identity(value) { + return value; + } + + /** + * Adds functions properties of `object` to the `lodash` function and chainable + * wrapper. + * + * @static + * @memberOf _ + * @category Utilities + * @param {Object} object The object of function properties to add to `lodash`. + * @example + * + * _.mixin({ + * 'capitalize': function(string) { + * return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase(); + * } + * }); + * + * _.capitalize('curly'); + * // => 'Curly' + * + * _('larry').capitalize(); + * // => 'Larry' + */ + function mixin(object) { + forEach(functions(object), function(name){ + addToWrapper(name, lodash[name] = object[name]); + }); + } + + /** + * Reverts the '_' variable to its previous value and returns a reference to + * the `lodash` function. + * + * @static + * @memberOf _ + * @category Utilities + * @returns {Function} Returns the `lodash` function. + * @example + * + * var lodash = _.noConflict(); + */ + function noConflict() { + window['_'] = oldDash; + return this; + } + + /** + * 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. + * + * @static + * @memberOf _ + * @category Utilities + * @param {Object} object The object to inspect. + * @param {String} property The property to get the result of. + * @returns {Mixed} Returns the resolved. + * @example + * + * var object = { + * 'cheese': 'crumpets', + * 'stuff': function() { + * return 'nonsense'; + * } + * }; + * + * _.result(object, 'cheese'); + * // => 'crumpets' + * + * _.result(object, 'stuff'); + * // => 'nonsense' + */ + function result(object, property) { + if (object == null) return null; + var value = object[property]; + return isFunction(value) ? object[property]() : value; + } + + /** + * Executes the `callback` function `n` times. + * + * @static + * @memberOf _ + * @category Utilities + * @param {Number} n The number of times to execute the callback. + * @param {Function} callback The function called per iteration. + * @param {Mixed} [thisArg] The `this` binding for the callback. + * @example + * + * _.times(3, function() { genie.grantWish(); }); + */ + function times(n, callback, thisArg) { + for (var index = 0; index < n; index++) { + callback.call(thisArg, index); + } + } + + /** + * Generates a unique id. If `prefix` is passed, the id will be appended to it. + * + * @static + * @memberOf _ + * @category Utilities + * @param {String} [prefix] The value to prefix the id with. + * @returns {Number|String} Returns a numeric id if no prefix is passed, else + * a string id may be returned. + * @example + * + * _.uniqueId('contact_'); + * // => 'contact_104' + */ + function uniqueId(prefix) { + var id = idCounter++; + return prefix ? prefix + id : id; + } + + /*--------------------------------------------------------------------------*/ + + /** + * JavaScript micro-templating, similar to John Resig's implementation. + * Lo-Dash templating handles arbitrary delimiters, preserves whitespace, + * and correctly escapes quotes within interpolated code. + * + * @static + * @memberOf _ + * @category Utilities + * @param {String} text The + * @param {Obect} data The + * @param {Object} settings + * @returns {String} Returns.... + * @example + * + * var compiled = _.template('hello: <%= name %>'); + * compiled({ 'name': 'moe' }); + * // => 'hello: moe' + * + * var list = '% _.forEach(people, function(name) { %>
  • <%= name %>
  • <% }); %>'; + * _.template(list, { 'people': ['moe', 'curly', 'larry'] }); + * // => '
  • moe
  • curly
  • larry
  • ' + * + * var template = _.template('<%- value %>'); + * template({ 'value': ' + */ + function template(text, data, settings) { + settings = defaults(settings || {}, lodash.templateSettings); + + // Compile the template source, taking care to escape characters that + // cannot be included in a string literal and then unescape them in code + // blocks. + var source = "__p+='" + text + .replace(escaper, function(match) { + return '\\' + escapes[match]; + }) + .replace(settings.escape || noMatch, function(match, code) { + return "'+\n_.escape(" + unescape(code) + ")+\n'"; + }) + .replace(settings.interpolate || noMatch, function(match, code) { + return "'+\n(" + unescape(code) + ")+\n'"; + }) + .replace(settings.evaluate || noMatch, function(match, code) { + return "';\n" + unescape(code) + "\n;__p+='"; + }) + "';\n"; + + // If a variable is not specified, place data values in local scope. + if (!settings.variable) { + source = 'with(object||{}){\n' + source + '}\n'; + } + + source = "var __p='';" + + "var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n" + + source + "return __p;\n"; + + var render = Function(settings.variable || 'object', '_', source); + if (data) { + return render(data, lodash); + } + + var template = function(data) { + return render.call(this, data, lodash); + }; + // Provide the compiled function source as a convenience for build time + // precompilation. + template.source = 'function(' + (settings.variable || 'object') + '){\n' + + source + '}'; + + return template; + } + + /*--------------------------------------------------------------------------*/ + + /** + * Wraps the value in a `lodash` chainable object. + * + * @static + * @memberOf _ + * @category Chaining + * @param {Mixed} value The value to wrap. + * @returns {Object} Returns the `lodash` chainable object. + * @example + * + * var stooges = [ + * { 'name' : 'moe', 'age' : 40}, + * { 'name' : 'larry', 'age' : 50}, + * { 'name' : 'curly', 'age' : 60} + * ]; + * + * var youngest = _.chain(stooges) + * .sortBy(function(stooge){ return stooge.age; }) + * .map(function(stooge){ return stooge.name + ' is ' + stooge.age; }) + * .first() + * .value(); + * // => 'moe is 40' + */ + function chain(value) { + return lodash(value).chain(); + } + + /** + * Extracts the value from a wrapped chainable object. + * + * @name chain + * @memberOf _ + * @category Chaining + * @returns {Mixed} Returns the wrapped object. + * @example + * + * _([1, 2, 3]).value(); + * // => [1, 2, 3] + */ + function chainWrapper() { + this._chain = true; + return this; + } + + /** + * Extracts the value from a wrapped chainable object. + * + * @memberOf _ + * @category Chaining + * @returns {Mixed} Returns the wrapped object. + * @example + * + * _([1, 2, 3]).value(); + * // => [1, 2, 3] + */ + function value() { + return this._wrapped; + } + + /*--------------------------------------------------------------------------*/ + + /* + _.keys = nativeKeys || + + _.isArray = nativeIsArray || function(collection) { + if (!isArguments(arguments)) { + _.isArguments = function(collection) { + return !!(collection && hasOwnProperty.call(collection, 'callee')); + }; + } + */ + + /*--------------------------------------------------------------------------*/ + + /** + * The semantic version number. + * + * @static + * @memberOf _ + * @type String + */ + lodash.VERSION = '1.3.3'; + + /** + * By default, Lodash uses ERB-style template delimiters, change the following + * template settings to use alternative delimiters. + * + * @static + * @memberOf _ + * @type Object + */ + lodash.templateSettings = { + 'evaluate': /<%([\s\S]+?)%>/g, + 'interpolate': /<%=([\s\S]+?)%>/g, + 'escape': /<%-([\s\S]+?)%>/g + }; + + // assign static properties + extend(lodash, { + 'after': after, + 'bind': bind, + 'bindAll': bindAll, + 'chain': chain, + 'clone': clone, + 'compact': compact, + 'compose': compose, + 'contains': contains, + 'debounce': debounce, + 'defaults': defaults, + 'defer': defer, + 'delay': delay, + 'difference': difference, + 'escape': escape, + 'every': every, + 'extend': extend, + 'filter': filter, + 'find': find, + 'first': first, + 'flatten': flatten, + 'forEach': forEach, + 'functions': functions, + 'groupBy': groupBy, + 'has': has, + 'identity': identity, + 'indexOf': indexOf, + 'initial': initial, + 'intersection': intersection, + 'invoke': invoke, + 'isArguments': isArguments, + 'isArray': isArray, + 'isBoolean': isBoolean, + 'isDate': isDate, + 'isElement': isElement, + 'isEmpty': isEmpty, + 'isEqual': isEqual, + 'isFinite': isFinite, + 'isFunction': isFunction, + 'isNaN': isNaN, + 'isNull': isNull, + 'isNumber': isNumber, + 'isObject': isObject, + 'isRegExp': isRegExp, + 'isString': isString, + 'isUndefined': isUndefined, + 'keys': keys, + 'last': last, + 'lastIndexOf': lastIndexOf, + 'map': map, + 'max': max, + 'memoize': memoize, + 'min': min, + 'mixin': mixin, + 'noConflict': noConflict, + 'once': once, + 'pick': pick, + 'pluck': pluck, + 'range': range, + 'reduce': reduce, + 'reduceRight': reduceRight, + 'reject': reject, + 'rest': rest, + 'result': result, + 'shuffle': shuffle, + 'size': size, + 'some': some, + 'sortBy': sortBy, + 'sortedIndex': sortedIndex, + 'tap': tap, + 'template': template, + 'throttle': throttle, + 'times': times, + 'toArray': toArray, + 'union': union, + 'uniq': uniq, + 'uniqueId': uniqueId, + 'values': values, + 'without': without, + 'wrap': wrap, + 'zip': zip + }); + + // assign aliases + extend(lodash, { + 'all': every, + 'any': some, + 'collect': map, + 'detect': find, + 'each': forEach, + 'foldl': reduce, + 'foldr': reduceRight, + 'head': first, + 'include': contains, + 'inject': reduce, + 'intersect': intersection, + 'methods': functions, + 'select': filter, + 'tail': rest, + 'take': first, + 'unique': uniq + }); + + /*--------------------------------------------------------------------------*/ + + // Expose `wrapper.prototype` as `_.prototype` + lodash.prototype = Wrapper.prototype; + + // Add all of the Lo-Dash functions to the wrapper collection. + lodash.mixin(lodash); + + // Add all mutator Array functions to the wrapper. + forEach(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { + var method = ArrayProto[name]; + Wrapper.prototype[name] = function() { + var wrapped = this._wrapped; + method.apply(wrapped, arguments); + var length = wrapped.length; + if ((name == 'shift' || name == 'splice') && length === 0) delete wrapped[0]; + return resultWrapper(wrapped, this._chain); + }; + }); + + // Add all accessor Array functions to the wrapper. + forEach(['concat', 'join', 'slice'], function(name) { + var method = ArrayProto[name]; + Wrapper.prototype[name] = function() { + return resultWrapper(method.apply(this._wrapped, arguments), this._chain); + }; + }); + + extend(lodash.prototype, { + chain: chainWrapper, + value: value + }); + + /*--------------------------------------------------------------------------*/ + + // expose lodash + if (freeExports) { + // in Node.js or RingoJS v0.8.0+ + if (typeof module == 'object' && module && module.exports == freeExports) { + (module.exports = lodash)._ = lodash; + } + // in Narwhal or RingoJS v0.7.0- + else { + freeExports._ = lodash; + } + } + // via an AMD loader + else if (typeof define == 'function' && typeof define.amd == 'object' && define.amd && define.amd.lodash) { + define('lodash', function() { + return lodash; + }); + } + // in a browser or Rhino + else { + // use square bracket notation so Closure Compiler won't munge `_` + // http://code.google.com/closure/compiler/docs/api-tutorial3.html#export + window['_'] = lodash; + } +}(this)); diff --git a/package.json b/package.json index c573dae45..660095338 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,42 @@ { - "name" : "underscore", - "description" : "JavaScript's functional programming helper library.", - "homepage" : "http://documentcloud.github.com/underscore/", - "keywords" : ["util", "functional", "server", "client", "browser"], - "author" : "Jeremy Ashkenas ", - "repository" : {"type": "git", "url": "git://github.com/documentcloud/underscore.git"}, - "main" : "underscore.js", - "version" : "1.3.3" -} + "name": "lodash", + "version": "0.1.0", + "description": "TBD", + "homepage": "https://github.com/bestiejs/lodash", + "main": "lodash", + "keywords": [ + "browser", + "client", + "functional", + "performance", + "server", + "speed", + "util" + ], + "licenses": [ + { + "type": "MIT", + "url": "http://mths.be/mit" + } + ], + "author": { + "name": "John-David Dalton", + "email": "john@fusejs.com", + "web": "http://allyoucanleet.com/" + }, + "bugs": { + "url": "https://github.com/bestiejs/lodash/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/bestiejs/lodash.git" + }, + "engines": [ + "node", + "rhino" + ], + "directories": { + "doc": "./doc", + "test": "./test" + } +} \ No newline at end of file diff --git a/test/index.html b/test/index.html index cab8dbdbc..4a1b117a1 100644 --- a/test/index.html +++ b/test/index.html @@ -2,18 +2,18 @@ - LowDash.js Test Suite + Lo-Dash Test Suite -

    LowDash.js Test Suite

    +

    Lo-Dash Test Suite

      - - + + - + diff --git a/underscore.js b/underscore.js deleted file mode 100644 index f6f7e2f23..000000000 --- a/underscore.js +++ /dev/null @@ -1,1059 +0,0 @@ -// Underscore.js 1.3.3 -// (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. -// Underscore is freely distributable under the MIT license. -// Portions of Underscore are inspired or borrowed from Prototype, -// Oliver Steele's Functional, and John Resig's Micro-Templating. -// For all details and documentation: -// http://documentcloud.github.com/underscore - -(function() { - - // Baseline setup - // -------------- - - // Establish the root object, `window` in the browser, or `global` on the server. - var root = this; - - // Save the previous value of the `_` variable. - var previousUnderscore = root._; - - // Establish the object that gets returned to break out of a loop iteration. - var breaker = {}; - - // Save bytes in the minified (but not gzipped) version: - var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; - - // Create quick reference variables for speed access to core prototypes. - var slice = ArrayProto.slice, - unshift = ArrayProto.unshift, - toString = ObjProto.toString, - hasOwnProperty = ObjProto.hasOwnProperty; - - // All **ECMAScript 5** native function implementations that we hope to use - // are declared here. - var - nativeForEach = ArrayProto.forEach, - nativeMap = ArrayProto.map, - nativeReduce = ArrayProto.reduce, - nativeReduceRight = ArrayProto.reduceRight, - nativeFilter = ArrayProto.filter, - nativeEvery = ArrayProto.every, - nativeSome = ArrayProto.some, - nativeIndexOf = ArrayProto.indexOf, - nativeLastIndexOf = ArrayProto.lastIndexOf, - nativeIsArray = Array.isArray, - nativeKeys = Object.keys, - nativeBind = FuncProto.bind; - - // Create a safe reference to the Underscore object for use below. - var _ = function(obj) { return new wrapper(obj); }; - - // Export the Underscore object for **Node.js**, with - // backwards-compatibility for the old `require()` API. If we're in - // the browser, add `_` as a global object via a string identifier, - // for Closure Compiler "advanced" mode. - if (typeof exports !== 'undefined') { - if (typeof module !== 'undefined' && module.exports) { - exports = module.exports = _; - } - exports._ = _; - } else { - root['_'] = _; - } - - // Current version. - _.VERSION = '1.3.3'; - - // Collection Functions - // -------------------- - - // The cornerstone, an `each` implementation, aka `forEach`. - // Handles objects with the built-in `forEach`, arrays, and raw objects. - // Delegates to **ECMAScript 5**'s native `forEach` if available. - var each = _.each = _.forEach = function(obj, iterator, context) { - if (obj == null) return; - if (nativeForEach && obj.forEach === nativeForEach) { - obj.forEach(iterator, context); - } else if (obj.length === +obj.length) { - for (var i = 0, l = obj.length; i < l; i++) { - if (i in obj && iterator.call(context, obj[i], i, obj) === breaker) return; - } - } else { - for (var key in obj) { - if (_.has(obj, key)) { - if (iterator.call(context, obj[key], key, obj) === breaker) return; - } - } - } - }; - - // Return the results of applying the iterator to each element. - // Delegates to **ECMAScript 5**'s native `map` if available. - _.map = _.collect = function(obj, iterator, context) { - var results = []; - if (obj == null) return results; - if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context); - each(obj, function(value, index, list) { - results[results.length] = iterator.call(context, value, index, list); - }); - if (obj.length === +obj.length) results.length = obj.length; - return results; - }; - - // **Reduce** builds up a single result from a list of values, aka `inject`, - // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available. - _.reduce = _.foldl = _.inject = function(obj, iterator, memo, context) { - var initial = arguments.length > 2; - if (obj == null) obj = []; - if (nativeReduce && obj.reduce === nativeReduce) { - if (context) iterator = _.bind(iterator, context); - return initial ? obj.reduce(iterator, memo) : obj.reduce(iterator); - } - each(obj, function(value, index, list) { - if (!initial) { - memo = value; - initial = true; - } else { - memo = iterator.call(context, memo, value, index, list); - } - }); - if (!initial) throw new TypeError('Reduce of empty array with no initial value'); - return memo; - }; - - // The right-associative version of reduce, also known as `foldr`. - // Delegates to **ECMAScript 5**'s native `reduceRight` if available. - _.reduceRight = _.foldr = function(obj, iterator, memo, context) { - var initial = arguments.length > 2; - if (obj == null) obj = []; - if (nativeReduceRight && obj.reduceRight === nativeReduceRight) { - if (context) iterator = _.bind(iterator, context); - return initial ? obj.reduceRight(iterator, memo) : obj.reduceRight(iterator); - } - var reversed = _.toArray(obj).reverse(); - if (context && !initial) iterator = _.bind(iterator, context); - return initial ? _.reduce(reversed, iterator, memo, context) : _.reduce(reversed, iterator); - }; - - // Return the first value which passes a truth test. Aliased as `detect`. - _.find = _.detect = function(obj, iterator, context) { - var result; - any(obj, function(value, index, list) { - if (iterator.call(context, value, index, list)) { - result = value; - return true; - } - }); - return result; - }; - - // Return all the elements that pass a truth test. - // Delegates to **ECMAScript 5**'s native `filter` if available. - // Aliased as `select`. - _.filter = _.select = function(obj, iterator, context) { - var results = []; - if (obj == null) return results; - if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context); - each(obj, function(value, index, list) { - if (iterator.call(context, value, index, list)) results[results.length] = value; - }); - return results; - }; - - // Return all the elements for which a truth test fails. - _.reject = function(obj, iterator, context) { - var results = []; - if (obj == null) return results; - each(obj, function(value, index, list) { - if (!iterator.call(context, value, index, list)) results[results.length] = value; - }); - return results; - }; - - // Determine whether all of the elements match a truth test. - // Delegates to **ECMAScript 5**'s native `every` if available. - // Aliased as `all`. - _.every = _.all = function(obj, iterator, context) { - var result = true; - if (obj == null) return result; - if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context); - each(obj, function(value, index, list) { - if (!(result = result && iterator.call(context, value, index, list))) return breaker; - }); - return !!result; - }; - - // Determine if at least one element in the object matches a truth test. - // Delegates to **ECMAScript 5**'s native `some` if available. - // Aliased as `any`. - var any = _.some = _.any = function(obj, iterator, context) { - iterator || (iterator = _.identity); - var result = false; - if (obj == null) return result; - if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context); - each(obj, function(value, index, list) { - if (result || (result = iterator.call(context, value, index, list))) return breaker; - }); - return !!result; - }; - - // Determine if a given value is included in the array or object using `===`. - // Aliased as `contains`. - _.include = _.contains = function(obj, target) { - var found = false; - if (obj == null) return found; - if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1; - found = any(obj, function(value) { - return value === target; - }); - return found; - }; - - // Invoke a method (with arguments) on every item in a collection. - _.invoke = function(obj, method) { - var args = slice.call(arguments, 2); - return _.map(obj, function(value) { - return (_.isFunction(method) ? method || value : value[method]).apply(value, args); - }); - }; - - // Convenience version of a common use case of `map`: fetching a property. - _.pluck = function(obj, key) { - return _.map(obj, function(value){ return value[key]; }); - }; - - // Return the maximum element or (element-based computation). - _.max = function(obj, iterator, context) { - if (!iterator && _.isArray(obj) && obj[0] === +obj[0]) return Math.max.apply(Math, obj); - if (!iterator && _.isEmpty(obj)) return -Infinity; - var result = {computed : -Infinity}; - each(obj, function(value, index, list) { - var computed = iterator ? iterator.call(context, value, index, list) : value; - computed >= result.computed && (result = {value : value, computed : computed}); - }); - return result.value; - }; - - // Return the minimum element (or element-based computation). - _.min = function(obj, iterator, context) { - if (!iterator && _.isArray(obj) && obj[0] === +obj[0]) return Math.min.apply(Math, obj); - if (!iterator && _.isEmpty(obj)) return Infinity; - var result = {computed : Infinity}; - each(obj, function(value, index, list) { - var computed = iterator ? iterator.call(context, value, index, list) : value; - computed < result.computed && (result = {value : value, computed : computed}); - }); - return result.value; - }; - - // Shuffle an array. - _.shuffle = function(obj) { - var shuffled = [], rand; - each(obj, function(value, index, list) { - rand = Math.floor(Math.random() * (index + 1)); - shuffled[index] = shuffled[rand]; - shuffled[rand] = value; - }); - return shuffled; - }; - - // Sort the object's values by a criterion produced by an iterator. - _.sortBy = function(obj, val, context) { - var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; }; - return _.pluck(_.map(obj, function(value, index, list) { - return { - value : value, - criteria : iterator.call(context, value, index, list) - }; - }).sort(function(left, right) { - var a = left.criteria, b = right.criteria; - if (a === void 0) return 1; - if (b === void 0) return -1; - return a < b ? -1 : a > b ? 1 : 0; - }), 'value'); - }; - - // Groups the object's values by a criterion. Pass either a string attribute - // to group by, or a function that returns the criterion. - _.groupBy = function(obj, val) { - var result = {}; - var iterator = _.isFunction(val) ? val : function(obj) { return obj[val]; }; - each(obj, function(value, index) { - var key = iterator(value, index); - (result[key] || (result[key] = [])).push(value); - }); - return result; - }; - - // Use a comparator function to figure out at what index an object should - // be inserted so as to maintain order. Uses binary search. - _.sortedIndex = function(array, obj, iterator) { - iterator || (iterator = _.identity); - var low = 0, high = array.length; - while (low < high) { - var mid = (low + high) >> 1; - iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid; - } - return low; - }; - - // Safely convert anything iterable into a real, live array. - _.toArray = function(obj) { - if (!obj) return []; - if (_.isArray(obj)) return slice.call(obj); - if (_.isArguments(obj)) return slice.call(obj); - if (obj.toArray && _.isFunction(obj.toArray)) return obj.toArray(); - return _.values(obj); - }; - - // Return the number of elements in an object. - _.size = function(obj) { - return _.isArray(obj) ? obj.length : _.keys(obj).length; - }; - - // Array Functions - // --------------- - - // Get the first element of an array. Passing **n** will return the first N - // values in the array. Aliased as `head` and `take`. The **guard** check - // allows it to work with `_.map`. - _.first = _.head = _.take = function(array, n, guard) { - return (n != null) && !guard ? slice.call(array, 0, n) : array[0]; - }; - - // Returns everything but the last entry of the array. Especcialy useful on - // the arguments object. Passing **n** will return all the values in - // the array, excluding the last N. The **guard** check allows it to work with - // `_.map`. - _.initial = function(array, n, guard) { - return slice.call(array, 0, array.length - ((n == null) || guard ? 1 : n)); - }; - - // Get the last element of an array. Passing **n** will return the last N - // values in the array. The **guard** check allows it to work with `_.map`. - _.last = function(array, n, guard) { - if ((n != null) && !guard) { - return slice.call(array, Math.max(array.length - n, 0)); - } else { - return array[array.length - 1]; - } - }; - - // Returns everything but the first entry of the array. Aliased as `tail`. - // Especially useful on the arguments object. Passing an **index** will return - // the rest of the values in the array from that index onward. The **guard** - // check allows it to work with `_.map`. - _.rest = _.tail = function(array, index, guard) { - return slice.call(array, (index == null) || guard ? 1 : index); - }; - - // Trim out all falsy values from an array. - _.compact = function(array) { - return _.filter(array, function(value){ return !!value; }); - }; - - // Return a completely flattened version of an array. - _.flatten = function(array, shallow) { - return _.reduce(array, function(memo, value) { - if (_.isArray(value)) return memo.concat(shallow ? value : _.flatten(value)); - memo[memo.length] = value; - return memo; - }, []); - }; - - // Return a version of the array that does not contain the specified value(s). - _.without = function(array) { - return _.difference(array, slice.call(arguments, 1)); - }; - - // Produce a duplicate-free version of the array. If the array has already - // been sorted, you have the option of using a faster algorithm. - // Aliased as `unique`. - _.uniq = _.unique = function(array, isSorted, iterator) { - var initial = iterator ? _.map(array, iterator) : array; - var results = []; - // The `isSorted` flag is irrelevant if the array only contains two elements. - if (array.length < 3) isSorted = true; - _.reduce(initial, function (memo, value, index) { - if (isSorted ? _.last(memo) !== value || !memo.length : !_.include(memo, value)) { - memo.push(value); - results.push(array[index]); - } - return memo; - }, []); - return results; - }; - - // Produce an array that contains the union: each distinct element from all of - // the passed-in arrays. - _.union = function() { - return _.uniq(_.flatten(arguments, true)); - }; - - // Produce an array that contains every item shared between all the - // passed-in arrays. (Aliased as "intersect" for back-compat.) - _.intersection = _.intersect = function(array) { - var rest = slice.call(arguments, 1); - return _.filter(_.uniq(array), function(item) { - return _.every(rest, function(other) { - return _.indexOf(other, item) >= 0; - }); - }); - }; - - // Take the difference between one array and a number of other arrays. - // Only the elements present in just the first array will remain. - _.difference = function(array) { - var rest = _.flatten(slice.call(arguments, 1), true); - return _.filter(array, function(value){ return !_.include(rest, value); }); - }; - - // Zip together multiple lists into a single array -- elements that share - // an index go together. - _.zip = function() { - var args = slice.call(arguments); - var length = _.max(_.pluck(args, 'length')); - var results = new Array(length); - for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i); - return results; - }; - - // If the browser doesn't supply us with indexOf (I'm looking at you, **MSIE**), - // we need this function. Return the position of the first occurrence of an - // item in an array, or -1 if the item is not included in the array. - // Delegates to **ECMAScript 5**'s native `indexOf` if available. - // If the array is large and already in sort order, pass `true` - // for **isSorted** to use binary search. - _.indexOf = function(array, item, isSorted) { - if (array == null) return -1; - var i, l; - if (isSorted) { - i = _.sortedIndex(array, item); - return array[i] === item ? i : -1; - } - if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item); - for (i = 0, l = array.length; i < l; i++) if (i in array && array[i] === item) return i; - return -1; - }; - - // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available. - _.lastIndexOf = function(array, item) { - if (array == null) return -1; - if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item); - var i = array.length; - while (i--) if (i in array && array[i] === item) return i; - return -1; - }; - - // Generate an integer Array containing an arithmetic progression. A port of - // the native Python `range()` function. See - // [the Python documentation](http://docs.python.org/library/functions.html#range). - _.range = function(start, stop, step) { - if (arguments.length <= 1) { - stop = start || 0; - start = 0; - } - step = arguments[2] || 1; - - var len = Math.max(Math.ceil((stop - start) / step), 0); - var idx = 0; - var range = new Array(len); - - while(idx < len) { - range[idx++] = start; - start += step; - } - - return range; - }; - - // Function (ahem) Functions - // ------------------ - - // Reusable constructor function for prototype setting. - var ctor = function(){}; - - // Create a function bound to a given object (assigning `this`, and arguments, - // optionally). Binding with arguments is also known as `curry`. - // Delegates to **ECMAScript 5**'s native `Function.bind` if available. - // We check for `func.bind` first, to fail fast when `func` is undefined. - _.bind = function bind(func, context) { - var bound, args; - if (func.bind === nativeBind && nativeBind) return nativeBind.apply(func, slice.call(arguments, 1)); - if (!_.isFunction(func)) throw new TypeError; - args = slice.call(arguments, 2); - return bound = function() { - if (!(this instanceof bound)) return func.apply(context, args.concat(slice.call(arguments))); - ctor.prototype = func.prototype; - var self = new ctor; - var result = func.apply(self, args.concat(slice.call(arguments))); - if (Object(result) === result) return result; - return self; - }; - }; - - // Bind all of an object's methods to that object. Useful for ensuring that - // all callbacks defined on an object belong to it. - _.bindAll = function(obj) { - var funcs = slice.call(arguments, 1); - if (funcs.length == 0) funcs = _.functions(obj); - each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); }); - return obj; - }; - - // Memoize an expensive function by storing its results. - _.memoize = function(func, hasher) { - var memo = {}; - hasher || (hasher = _.identity); - return function() { - var key = hasher.apply(this, arguments); - return _.has(memo, key) ? memo[key] : (memo[key] = func.apply(this, arguments)); - }; - }; - - // Delays a function for the given number of milliseconds, and then calls - // it with the arguments supplied. - _.delay = function(func, wait) { - var args = slice.call(arguments, 2); - return setTimeout(function(){ return func.apply(null, args); }, wait); - }; - - // Defers a function, scheduling it to run after the current call stack has - // cleared. - _.defer = function(func) { - return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1))); - }; - - // Returns a function, that, when invoked, will only be triggered at most once - // during a given window of time. - _.throttle = function(func, wait) { - var context, args, timeout, throttling, more, result; - var whenDone = _.debounce(function(){ more = throttling = false; }, wait); - return function() { - context = this; args = arguments; - var later = function() { - timeout = null; - if (more) func.apply(context, args); - whenDone(); - }; - if (!timeout) timeout = setTimeout(later, wait); - if (throttling) { - more = true; - } else { - result = func.apply(context, args); - } - whenDone(); - throttling = true; - return result; - }; - }; - - // Returns a function, that, as long as it continues to be invoked, will not - // be triggered. The function will be called after it stops being called for - // N milliseconds. If `immediate` is passed, trigger the function on the - // leading edge, instead of the trailing. - _.debounce = function(func, wait, immediate) { - var timeout; - return function() { - var context = this, args = arguments; - var later = function() { - timeout = null; - if (!immediate) func.apply(context, args); - }; - if (immediate && !timeout) func.apply(context, args); - clearTimeout(timeout); - timeout = setTimeout(later, wait); - }; - }; - - // Returns a function that will be executed at most one time, no matter how - // often you call it. Useful for lazy initialization. - _.once = function(func) { - var ran = false, memo; - return function() { - if (ran) return memo; - ran = true; - return memo = func.apply(this, arguments); - }; - }; - - // Returns the first function passed as an argument to the second, - // allowing you to adjust arguments, run code before and after, and - // conditionally execute the original function. - _.wrap = function(func, wrapper) { - return function() { - var args = [func].concat(slice.call(arguments, 0)); - return wrapper.apply(this, args); - }; - }; - - // Returns a function that is the composition of a list of functions, each - // consuming the return value of the function that follows. - _.compose = function() { - var funcs = arguments; - return function() { - var args = arguments; - for (var i = funcs.length - 1; i >= 0; i--) { - args = [funcs[i].apply(this, args)]; - } - return args[0]; - }; - }; - - // Returns a function that will only be executed after being called N times. - _.after = function(times, func) { - if (times <= 0) return func(); - return function() { - if (--times < 1) { return func.apply(this, arguments); } - }; - }; - - // Object Functions - // ---------------- - - // Retrieve the names of an object's properties. - // Delegates to **ECMAScript 5**'s native `Object.keys` - _.keys = nativeKeys || function(obj) { - if (obj !== Object(obj)) throw new TypeError('Invalid object'); - var keys = []; - for (var key in obj) if (_.has(obj, key)) keys[keys.length] = key; - return keys; - }; - - // Retrieve the values of an object's properties. - _.values = function(obj) { - return _.map(obj, _.identity); - }; - - // Return a sorted list of the function names available on the object. - // Aliased as `methods` - _.functions = _.methods = function(obj) { - var names = []; - for (var key in obj) { - if (_.isFunction(obj[key])) names.push(key); - } - return names.sort(); - }; - - // Extend a given object with all the properties in passed-in object(s). - _.extend = function(obj) { - each(slice.call(arguments, 1), function(source) { - for (var prop in source) { - obj[prop] = source[prop]; - } - }); - return obj; - }; - - // Return a copy of the object only containing the whitelisted properties. - _.pick = function(obj) { - var result = {}; - each(_.flatten(slice.call(arguments, 1)), function(key) { - if (key in obj) result[key] = obj[key]; - }); - return result; - }; - - // Fill in a given object with default properties. - _.defaults = function(obj) { - each(slice.call(arguments, 1), function(source) { - for (var prop in source) { - if (obj[prop] == null) obj[prop] = source[prop]; - } - }); - return obj; - }; - - // Create a (shallow-cloned) duplicate of an object. - _.clone = function(obj) { - if (!_.isObject(obj)) return obj; - return _.isArray(obj) ? obj.slice() : _.extend({}, obj); - }; - - // Invokes interceptor with the obj, and then returns obj. - // The primary purpose of this method is to "tap into" a method chain, in - // order to perform operations on intermediate results within the chain. - _.tap = function(obj, interceptor) { - interceptor(obj); - return obj; - }; - - // Internal recursive comparison function. - function eq(a, b, stack) { - // Identical objects are equal. `0 === -0`, but they aren't identical. - // See the Harmony `egal` proposal: http://wiki.ecmascript.org/doku.php?id=harmony:egal. - if (a === b) return a !== 0 || 1 / a == 1 / b; - // A strict comparison is necessary because `null == undefined`. - if (a == null || b == null) return a === b; - // Unwrap any wrapped objects. - if (a._chain) a = a._wrapped; - if (b._chain) b = b._wrapped; - // Invoke a custom `isEqual` method if one is provided. - if (a.isEqual && _.isFunction(a.isEqual)) return a.isEqual(b); - if (b.isEqual && _.isFunction(b.isEqual)) return b.isEqual(a); - // Compare `[[Class]]` names. - var className = toString.call(a); - if (className != toString.call(b)) return false; - switch (className) { - // Strings, numbers, dates, and booleans are compared by value. - case '[object String]': - // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is - // equivalent to `new String("5")`. - return a == String(b); - case '[object Number]': - // `NaN`s are equivalent, but non-reflexive. An `egal` comparison is performed for - // other numeric values. - return a != +a ? b != +b : (a == 0 ? 1 / a == 1 / b : a == +b); - case '[object Date]': - case '[object Boolean]': - // Coerce dates and booleans to numeric primitive values. Dates are compared by their - // millisecond representations. Note that invalid dates with millisecond representations - // of `NaN` are not equivalent. - return +a == +b; - // RegExps are compared by their source patterns and flags. - case '[object RegExp]': - return a.source == b.source && - a.global == b.global && - a.multiline == b.multiline && - a.ignoreCase == b.ignoreCase; - } - if (typeof a != 'object' || typeof b != 'object') return false; - // Assume equality for cyclic structures. The algorithm for detecting cyclic - // structures is adapted from ES 5.1 section 15.12.3, abstract operation `JO`. - var length = stack.length; - while (length--) { - // Linear search. Performance is inversely proportional to the number of - // unique nested structures. - if (stack[length] == a) return true; - } - // Add the first object to the stack of traversed objects. - stack.push(a); - var size = 0, result = true; - // Recursively compare objects and arrays. - if (className == '[object Array]') { - // Compare array lengths to determine if a deep comparison is necessary. - size = a.length; - result = size == b.length; - if (result) { - // Deep compare the contents, ignoring non-numeric properties. - while (size--) { - // Ensure commutative equality for sparse arrays. - if (!(result = size in a == size in b && eq(a[size], b[size], stack))) break; - } - } - } else { - // Objects with different constructors are not equivalent. - if ('constructor' in a != 'constructor' in b || a.constructor != b.constructor) return false; - // Deep compare objects. - for (var key in a) { - if (_.has(a, key)) { - // Count the expected number of properties. - size++; - // Deep compare each member. - if (!(result = _.has(b, key) && eq(a[key], b[key], stack))) break; - } - } - // Ensure that both objects contain the same number of properties. - if (result) { - for (key in b) { - if (_.has(b, key) && !(size--)) break; - } - result = !size; - } - } - // Remove the first object from the stack of traversed objects. - stack.pop(); - return result; - } - - // Perform a deep comparison to check if two objects are equal. - _.isEqual = function(a, b) { - return eq(a, b, []); - }; - - // Is a given array, string, or object empty? - // An "empty" object has no enumerable own-properties. - _.isEmpty = function(obj) { - if (obj == null) return true; - if (_.isArray(obj) || _.isString(obj)) return obj.length === 0; - for (var key in obj) if (_.has(obj, key)) return false; - return true; - }; - - // Is a given value a DOM element? - _.isElement = function(obj) { - return !!(obj && obj.nodeType == 1); - }; - - // Is a given value an array? - // Delegates to ECMA5's native Array.isArray - _.isArray = nativeIsArray || function(obj) { - return toString.call(obj) == '[object Array]'; - }; - - // Is a given variable an object? - _.isObject = function(obj) { - return obj === Object(obj); - }; - - // Is a given variable an arguments object? - _.isArguments = function(obj) { - return toString.call(obj) == '[object Arguments]'; - }; - if (!_.isArguments(arguments)) { - _.isArguments = function(obj) { - return !!(obj && _.has(obj, 'callee')); - }; - } - - // Is a given value a function? - _.isFunction = function(obj) { - return toString.call(obj) == '[object Function]'; - }; - - // Is a given value a string? - _.isString = function(obj) { - return toString.call(obj) == '[object String]'; - }; - - // Is a given value a number? - _.isNumber = function(obj) { - return toString.call(obj) == '[object Number]'; - }; - - // Is a given object a finite number? - _.isFinite = function(obj) { - return _.isNumber(obj) && isFinite(obj); - }; - - // Is the given value `NaN`? - _.isNaN = function(obj) { - // `NaN` is the only value for which `===` is not reflexive. - return obj !== obj; - }; - - // Is a given value a boolean? - _.isBoolean = function(obj) { - return obj === true || obj === false || toString.call(obj) == '[object Boolean]'; - }; - - // Is a given value a date? - _.isDate = function(obj) { - return toString.call(obj) == '[object Date]'; - }; - - // Is the given value a regular expression? - _.isRegExp = function(obj) { - return toString.call(obj) == '[object RegExp]'; - }; - - // Is a given value equal to null? - _.isNull = function(obj) { - return obj === null; - }; - - // Is a given variable undefined? - _.isUndefined = function(obj) { - return obj === void 0; - }; - - // Has own property? - _.has = function(obj, key) { - return hasOwnProperty.call(obj, key); - }; - - // Utility Functions - // ----------------- - - // Run Underscore.js in *noConflict* mode, returning the `_` variable to its - // previous owner. Returns a reference to the Underscore object. - _.noConflict = function() { - root._ = previousUnderscore; - return this; - }; - - // Keep the identity function around for default iterators. - _.identity = function(value) { - return value; - }; - - // Run a function **n** times. - _.times = function (n, iterator, context) { - for (var i = 0; i < n; i++) iterator.call(context, i); - }; - - // Escape a string for HTML interpolation. - _.escape = function(string) { - return (''+string).replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, ''').replace(/\//g,'/'); - }; - - // If the value of the named property is a function then invoke it; - // otherwise, return it. - _.result = function(object, property) { - if (object == null) return null; - var value = object[property]; - return _.isFunction(value) ? value.call(object) : value; - }; - - // Add your own custom functions to the Underscore object, ensuring that - // they're correctly added to the OOP wrapper as well. - _.mixin = function(obj) { - each(_.functions(obj), function(name){ - addToWrapper(name, _[name] = obj[name]); - }); - }; - - // Generate a unique integer id (unique within the entire client session). - // Useful for temporary DOM ids. - var idCounter = 0; - _.uniqueId = function(prefix) { - var id = idCounter++; - return prefix ? prefix + id : id; - }; - - // By default, Underscore uses ERB-style template delimiters, change the - // following template settings to use alternative delimiters. - _.templateSettings = { - evaluate : /<%([\s\S]+?)%>/g, - interpolate : /<%=([\s\S]+?)%>/g, - escape : /<%-([\s\S]+?)%>/g - }; - - // When customizing `templateSettings`, if you don't want to define an - // interpolation, evaluation or escaping regex, we need one that is - // guaranteed not to match. - var noMatch = /.^/; - - // Certain characters need to be escaped so that they can be put into a - // string literal. - var escapes = { - '\\': '\\', - "'": "'", - 'r': '\r', - 'n': '\n', - 't': '\t', - 'u2028': '\u2028', - 'u2029': '\u2029' - }; - - for (var p in escapes) escapes[escapes[p]] = p; - var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g; - var unescaper = /\\(\\|'|r|n|t|u2028|u2029)/g; - - // Within an interpolation, evaluation, or escaping, remove HTML escaping - // that had been previously added. - var unescape = function(code) { - return code.replace(unescaper, function(match, escape) { - return escapes[escape]; - }); - }; - - // JavaScript micro-templating, similar to John Resig's implementation. - // Underscore templating handles arbitrary delimiters, preserves whitespace, - // and correctly escapes quotes within interpolated code. - _.template = function(text, data, settings) { - settings = _.defaults(settings || {}, _.templateSettings); - - // Compile the template source, taking care to escape characters that - // cannot be included in a string literal and then unescape them in code - // blocks. - var source = "__p+='" + text - .replace(escaper, function(match) { - return '\\' + escapes[match]; - }) - .replace(settings.escape || noMatch, function(match, code) { - return "'+\n_.escape(" + unescape(code) + ")+\n'"; - }) - .replace(settings.interpolate || noMatch, function(match, code) { - return "'+\n(" + unescape(code) + ")+\n'"; - }) - .replace(settings.evaluate || noMatch, function(match, code) { - return "';\n" + unescape(code) + "\n;__p+='"; - }) + "';\n"; - - // If a variable is not specified, place data values in local scope. - if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n'; - - source = "var __p='';" + - "var print=function(){__p+=Array.prototype.join.call(arguments, '')};\n" + - source + "return __p;\n"; - - var render = new Function(settings.variable || 'obj', '_', source); - if (data) return render(data, _); - var template = function(data) { - return render.call(this, data, _); - }; - - // Provide the compiled function source as a convenience for build time - // precompilation. - template.source = 'function(' + (settings.variable || 'obj') + '){\n' + - source + '}'; - - return template; - }; - - // Add a "chain" function, which will delegate to the wrapper. - _.chain = function(obj) { - return _(obj).chain(); - }; - - // The OOP Wrapper - // --------------- - - // If Underscore is called as a function, it returns a wrapped object that - // can be used OO-style. This wrapper holds altered versions of all the - // underscore functions. Wrapped objects may be chained. - var wrapper = function(obj) { this._wrapped = obj; }; - - // Expose `wrapper.prototype` as `_.prototype` - _.prototype = wrapper.prototype; - - // Helper function to continue chaining intermediate results. - var result = function(obj, chain) { - return chain ? _(obj).chain() : obj; - }; - - // A method to easily add functions to the OOP wrapper. - var addToWrapper = function(name, func) { - wrapper.prototype[name] = function() { - var args = slice.call(arguments); - unshift.call(args, this._wrapped); - return result(func.apply(_, args), this._chain); - }; - }; - - // Add all of the Underscore functions to the wrapper object. - _.mixin(_); - - // Add all mutator Array functions to the wrapper. - each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) { - var method = ArrayProto[name]; - wrapper.prototype[name] = function() { - var wrapped = this._wrapped; - method.apply(wrapped, arguments); - var length = wrapped.length; - if ((name == 'shift' || name == 'splice') && length === 0) delete wrapped[0]; - return result(wrapped, this._chain); - }; - }); - - // Add all accessor Array functions to the wrapper. - each(['concat', 'join', 'slice'], function(name) { - var method = ArrayProto[name]; - wrapper.prototype[name] = function() { - return result(method.apply(this._wrapped, arguments), this._chain); - }; - }); - - // Start chaining a wrapped Underscore object. - wrapper.prototype.chain = function() { - this._chain = true; - return this; - }; - - // Extracts the result from a wrapped and chained object. - wrapper.prototype.value = function() { - return this._wrapped; - }; - -}).call(this);