diff --git a/doc/README.md b/doc/README.md index 6c1581137..4ea59bbb5 100644 --- a/doc/README.md +++ b/doc/README.md @@ -121,34 +121,29 @@ -### `_(value)` +### `_(value)` The Lodash function. [▲][1] #### Arguments -1. `value` *(Mixed)*: The value to wrap in a chainable `lowdash` object. +1. `value` *(Mixed)*: The value to wrap in a chainable `lodash` object. #### Returns *(Object)*: Returns a `lodash` instance. -#### Example -~~~ js - -~~~ - ## `_` -### `_(value)` +### `_(value)` The Lodash function. [▲][1] -### `_.VERSION` +### `_.VERSION` *(String)*: The semantic version number. [▲][1] @@ -157,7 +152,7 @@ The Lodash function. -### `_.after(times, func)` +### `_.after(times, func)` Creates a new function that is restricted to executing only after it is called a given number of `times`. [▲][1] @@ -182,7 +177,7 @@ _.forEach(notes, function(note) { -### `_.bind(func [, arg1, arg2, ...])` +### `_.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] @@ -195,7 +190,7 @@ Creates a new function that, when called, invokes `func` with the `this` binding #### Example ~~~ js -var func = function(greeting){ return greeting + ': ' + this.name; }; +var func = function(greeting) { return greeting + ': ' + this.name; }; func = _.bind(func, { 'name': 'moe' }, 'hi'); func(); // => 'hi: moe' @@ -206,7 +201,7 @@ func(); -### `_.bindAll(object [, methodName1, methodName2, ...])` +### `_.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] @@ -235,7 +230,7 @@ jQuery('#lodash_button').on('click', buttonView.onClick); -### `_.chain(value)` +### `_.chain(value)` Wraps the value in a `lodash` chainable object. [▲][1] @@ -248,14 +243,14 @@ Wraps the value in a `lodash` chainable object. #### Example ~~~ js var stooges = [ - { 'name' : 'moe', 'age' : 40}, - { 'name' : 'larry', 'age' : 50}, - { 'name' : 'curly', 'age' : 60} + { '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; }) + .sortBy(function(stooge) { return stooge.age; }) + .map(function(stooge) { return stooge.name + ' is ' + stooge.age; }) .first() .value(); // => 'moe is 40' @@ -266,7 +261,7 @@ var youngest = _.chain(stooges) -### `_.clone(value)` +### `_.clone(value)` Create a shallow clone of the `value`. Any nested objects or arrays will be assigned by reference and not cloned. [▲][1] @@ -287,7 +282,7 @@ _.clone({ 'name': 'moe' }); -### `_.compact(array)` +### `_.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] @@ -308,7 +303,7 @@ _.compact([0, 1, false, 2, '', 3]); -### `_.compose([func1, func2, ...])` +### `_.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] @@ -332,7 +327,7 @@ welcome('moe'); -### `_.contains(collection, target)` +### `_.contains(collection, target)` Checks if a given `target` value is present in a `collection` using strict equality for comparisons, i.e. `===`. [▲][1] @@ -354,7 +349,7 @@ _.contains([1, 2, 3], 3); -### `_.debounce(func, wait, immediate)` +### `_.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] @@ -377,7 +372,7 @@ jQuery(window).on('resize', lazyLayout); -### `_.defaults(object [, defaults1, defaults2, ..])` +### `_.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] @@ -400,7 +395,7 @@ _.defaults(iceCream, { 'flavor': 'vanilla', 'sprinkles': 'lots' }); -### `_.defer(func [, arg1, arg2, ...])` +### `_.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] @@ -413,7 +408,7 @@ Defers invoking the `func` function until the current call stack has cleared. Ad #### Example ~~~ js -_.defer(function(){ alert('deferred'); }); +_.defer(function() { alert('deferred'); }); // Returns from the function before the alert runs. ~~~ @@ -422,7 +417,7 @@ _.defer(function(){ alert('deferred'); }); -### `_.delay(func, wait [, arg1, arg2, ...])` +### `_.delay(func, wait [, arg1, arg2, ...])` Invokes the `func` function after `wait` milliseconds. Additional arguments are passed `func` when it is invoked. [▲][1] @@ -446,7 +441,7 @@ _.delay(log, 1000, 'logged later'); -### `_.difference(array [, array1, array2, ...])` +### `_.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] @@ -468,7 +463,7 @@ _.difference([1, 2, 3, 4, 5], [5, 2, 10]); -### `_.escape(string)` +### `_.escape(string)` Escapes a string for insertion into HTML, replacing `&`, `<`, `>`, `"`, `'`, and `/` characters. [▲][1] @@ -489,7 +484,7 @@ _.escape('Curly, Larry & Moe'); -### `_.every(collection, callback [, thisArg])` +### `_.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] @@ -512,7 +507,7 @@ _.every([true, 1, null, 'yes'], Boolean); -### `_.extend(destination [, source1, source2, ..])` +### `_.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] @@ -534,7 +529,7 @@ _.extend({ 'name': 'moe' }, { 'age': 40 }); -### `_.filter(collection, callback [, thisArg])` +### `_.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] @@ -557,7 +552,7 @@ var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }) -### `_.find(collection, callback [, thisArg])` +### `_.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] @@ -580,17 +575,17 @@ var even = _.find([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); -### `_.first(array [, n, guard])` +### `_.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`. +3. `[guard]` *(Object)*: Allows this method to work with others 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`. +*(Mixed)*: Returns the first value or an array of the first `n` values of the `array`. #### Example ~~~ js @@ -603,7 +598,7 @@ _.first([5, 4, 3, 2, 1]); -### `_.flatten(array, shallow)` +### `_.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] @@ -628,7 +623,7 @@ _.flatten([1, [2], [3, [[4]]]], true); -### `_.forEach(collection, callback [, thisArg])` +### `_.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] @@ -642,10 +637,10 @@ Iterates over a `collection`, executing the `callback` for each value in the `co #### Example ~~~ js -_.forforEach([1, 2, 3], function(num) { alert(num); }); +_.forEach([1, 2, 3], function(num) { alert(num); }); // => alerts each number in turn... -_.forforEach({ 'one' : 1, 'two' : 2, 'three' : 3}, function(num) { alert(num); }); +_.forEach({ 'one': 1, 'two': 2, 'three': 3}, function(num) { alert(num); }); // => alerts each number in turn... ~~~ @@ -654,7 +649,7 @@ _.forforEach({ 'one' : 1, 'two' : 2, 'three' : 3}, function(num) { alert(num); } -### `_.functions(object)` +### `_.functions(object)` Produces a sorted array of the `object`'s enumerable own property names that have function values. [▲][1] @@ -675,7 +670,7 @@ _.functions(_); -### `_.groupBy(collection, callback [, thisArg])` +### `_.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] @@ -701,7 +696,7 @@ _.groupBy(['one', 'two', 'three'], 'length'); -### `_.has(object, key)` +### `_.has(object, key)` Checks if an object has the specified key as a direct property. [▲][1] @@ -723,7 +718,7 @@ _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b'); -### `_.identity(value)` +### `_.identity(value)` This function simply returns the first argument passed to it. Note: It is used throughout Lodash as a default callback. [▲][1] @@ -745,7 +740,7 @@ moe === _.identity(moe); -### `_.indexOf(array, value [, isSorted=false])` +### `_.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] @@ -768,14 +763,14 @@ _.indexOf([1, 2, 3], 2); -### `_.initial(array [, n, guard])` +### `_.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`. +3. `[guard]` *(Object)*: Allows this method to work with others like `_.map` without using their callback `index` argument for `n`. #### Returns *(Array)*: Returns all but the last value or `n` values of the `array`. @@ -791,7 +786,7 @@ _.initial([5, 4, 3, 2, 1]); -### `_.intersection([array1, array2, ...])` +### `_.intersection([array1, array2, ...])` Computes the intersection of all the passed-in arrays. [▲][1] @@ -812,7 +807,7 @@ _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]); -### `_.invoke(collection, methodName [, arg1, arg2, ...])` +### `_.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] @@ -835,7 +830,7 @@ _.invoke([[5, 1, 7], [3, 2, 1]], 'sort'); -### `_.isArguments(value)` +### `_.isArguments(value)` Checks if a `value` is an `arguments` object. [▲][1] @@ -859,7 +854,7 @@ _.isArguments([1, 2, 3]); -### `_.isArray(value)` +### `_.isArray(value)` Checks if a `value` is an array. [▲][1] @@ -883,7 +878,7 @@ _.isArray([1, 2, 3]); -### `_.isBoolean(value)` +### `_.isBoolean(value)` Checks if a `value` is a boolean *(`true` or `false`)* value. [▲][1] @@ -904,7 +899,7 @@ _.isBoolean(null); -### `_.isDate(value)` +### `_.isDate(value)` Checks if a `value` is a date. [▲][1] @@ -925,7 +920,7 @@ _.isDate(new Date); -### `_.isElement(value)` +### `_.isElement(value)` Checks if a `value` is a DOM element. [▲][1] @@ -946,7 +941,7 @@ _.isElement(document.body); -### `_.isEmpty(value)` +### `_.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] @@ -970,13 +965,13 @@ _.isEmpty({}); -### `_.isEqual(value, other)` +### `_.isEqual(a, b)` 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. +1. `a` *(Mixed)*: The value to compare. +2. `b` *(Mixed)*: The other value to compare. #### Returns *(Boolean)*: Returns `true` if the values are equvalent, else `false`. @@ -998,7 +993,7 @@ _.isEqual(moe, clone); -### `_.isFinite(value)` +### `_.isFinite(value)` Checks if a `value` is a finite number. [▲][1] @@ -1025,7 +1020,7 @@ _.isFinite(Infinity); -### `_.isFunction(value)` +### `_.isFunction(value)` Checks if a `value` is a function. [▲][1] @@ -1046,7 +1041,7 @@ _.isFunction(''.concat); -### `_.isNaN(value)` +### `_.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] @@ -1061,6 +1056,9 @@ Checks if a `value` is `NaN`. Note: this is not the same as native `isNaN`, whic _.isNaN(NaN); // => true +_.isNaN(new Number(NaN)); +// => true + isNaN(undefined); // => true @@ -1073,7 +1071,7 @@ _.isNaN(undefined); -### `_.isNull(value)` +### `_.isNull(value)` Checks if a `value` is `null`. [▲][1] @@ -1097,7 +1095,7 @@ _.isNull(undefined); -### `_.isNumber(value)` +### `_.isNumber(value)` Checks if a `value` is a number. [▲][1] @@ -1118,7 +1116,7 @@ _.isNumber(8.4 * 5; -### `_.isObject(value)` +### `_.isObject(value)` Checks if a `value` is an object. [▲][1] @@ -1142,7 +1140,7 @@ _.isObject(1); -### `_.isRegExp(value)` +### `_.isRegExp(value)` Checks if a `value` is a regular expression. [▲][1] @@ -1163,7 +1161,7 @@ _.isRegExp(/moe/); -### `_.isString(value)` +### `_.isString(value)` Checks if a `value` is a string. [▲][1] @@ -1184,7 +1182,7 @@ _.isString('moe'); -### `_.isUndefined(value)` +### `_.isUndefined(value)` Checks if a `value` is `undefined`. [▲][1] @@ -1205,7 +1203,7 @@ _.isUndefined(void 0); -### `_.keys(object)` +### `_.keys(object)` Produces an array of the `object`'s enumerable own property names. [▲][1] @@ -1226,14 +1224,14 @@ _.keys({ 'one': 1, 'two': 2, 'three': 3 }); -### `_.last(array [, n, guard])` +### `_.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`. +3. `[guard]` *(Object)*: Allows this method to work with others like `_.map` without using their callback `index` argument for `n`. #### Returns *(Array)*: Returns all but the last value or `n` values of the `array`. @@ -1249,7 +1247,7 @@ _.last([5, 4, 3, 2, 1]); -### `_.lastIndexOf(array, value)` +### `_.lastIndexOf(array, value)` Gets the index at which the last occurrence of `value` is found using strict equality for comparisons, i.e. `===`. [▲][1] @@ -1271,7 +1269,7 @@ _.lastIndexOf([1, 2, 3, 1, 2, 3], 2); -### `_.map(collection, callback [, thisArg])` +### `_.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] @@ -1288,7 +1286,7 @@ Produces a new array of values by mapping each value in the `collection` through _.map([1, 2, 3], function(num) { return num * 3; }); // => [3, 6, 9] -_.map({ 'one' : 1, 'two' : 2, 'three' : 3 }, function(num) { return num * 3; }); +_.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; }); // => [3, 6, 9] ~~~ @@ -1297,7 +1295,7 @@ _.map({ 'one' : 1, 'two' : 2, 'three' : 3 }, function(num) { return num * 3; }); -### `_.max(collection [, callback, thisArg])` +### `_.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] @@ -1312,13 +1310,13 @@ Retrieves the maximum value of a `collection`. If `callback` is passed, it will #### Example ~~~ js var stooges = [ - { 'name' : 'moe', 'age' : 40}, - { 'name' : 'larry', 'age' : 50}, - { 'name' : 'curly', 'age' : 60} + { 'name': 'moe', 'age': 40 }, + { 'name': 'larry', 'age': 50 }, + { 'name': 'curly', 'age': 60 } ]; _.max(stooges, function(stooge) { return stooge.age; }); -// => { 'name' : 'curly', 'age' : 60 }; +// => { 'name': 'curly', 'age': 60 }; ~~~ @@ -1326,7 +1324,7 @@ _.max(stooges, function(stooge) { return stooge.age; }); -### `_.memoize(func [, hasher=_.identity])` +### `_.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] @@ -1349,7 +1347,7 @@ var fibonacci = _.memoize(function(n) { -### `_.min(collection [, callback, thisArg])` +### `_.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] @@ -1372,7 +1370,7 @@ _.min([10, 5, 100, 2, 1000]); -### `_.mixin(object)` +### `_.mixin(object)` Adds functions properties of `object` to the `lodash` function and chainable wrapper. [▲][1] @@ -1399,7 +1397,7 @@ _('larry').capitalize(); -### `_.noConflict()` +### `_.noConflict()` Reverts the '_' variable to its previous value and returns a reference to the `lodash` function. [▲][1] @@ -1416,7 +1414,7 @@ var lodash = _.noConflict(); -### `_.once(func)` +### `_.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] @@ -1439,7 +1437,7 @@ initialize(); -### `_.pick(object [, prop1, prop2, ..])` +### `_.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] @@ -1461,7 +1459,7 @@ _.pick({ 'name': 'moe', 'age': 40, 'userid': 'moe1' }, 'name', 'age'); -### `_.pluck(collection, property)` +### `_.pluck(collection, property)` Retrieves the value of a specified property from all values in a `collection`. [▲][1] @@ -1475,9 +1473,9 @@ Retrieves the value of a specified property from all values in a `collection`. #### Example ~~~ js var stooges = [ - { 'name' : 'moe', 'age' : 40}, - { 'name' : 'larry', 'age' : 50}, - { 'name' : 'curly', 'age' : 60} + { 'name': 'moe', 'age': 40 }, + { 'name': 'larry', 'age': 50 }, + { 'name': 'curly', 'age': 60 } ]; _.pluck(stooges, 'name'); @@ -1489,7 +1487,7 @@ _.pluck(stooges, 'name'); -### `_.range([start=0], end [, step=1])` +### `_.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] @@ -1524,7 +1522,7 @@ _.range(0); -### `_.reduce(collection, callback [, accumulator, thisArg])` +### `_.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] @@ -1548,7 +1546,7 @@ var sum = _.reduce([1, 2, 3], function(memo, num) { return memo + num; }); -### `_.reduceRight(collection, callback [, accumulator, thisArg])` +### `_.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] @@ -1573,7 +1571,7 @@ var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []); -### `_.reject(collection, callback [, thisArg])` +### `_.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] @@ -1596,14 +1594,14 @@ var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); -### `_.rest(array [, n, guard])` +### `_.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`. +3. `[guard]` *(Object)*: Allows this method to work with others like `_.map` without using their callback `index` argument for `n`. #### Returns *(Array)*: Returns all but the first value or `n` values of the `array`. @@ -1619,7 +1617,7 @@ _.rest([5, 4, 3, 2, 1]); -### `_.result(object, property)` +### `_.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] @@ -1651,7 +1649,7 @@ _.result(object, 'stuff'); -### `_.shuffle(collection)` +### `_.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] @@ -1672,7 +1670,7 @@ _.shuffle([1, 2, 3, 4, 5, 6]); -### `_.size(collection)` +### `_.size(collection)` Gets the number of values in the `collection`. [▲][1] @@ -1693,7 +1691,7 @@ _.size({ 'one': 1, 'two': 2, 'three': 3 }); -### `_.some(collection, callback [, thisArg])` +### `_.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] @@ -1716,7 +1714,7 @@ _.some([null, 0, 'yes', false]); -### `_.sortBy(collection, callback [, thisArg])` +### `_.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] @@ -1739,7 +1737,7 @@ _.sortBy([1, 2, 3, 4, 5, 6], function(num) { return Math.sin(num); }); -### `_.sortedIndex(array, value [, callback])` +### `_.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] @@ -1762,7 +1760,7 @@ _.sortedIndex([10, 20, 30, 40, 50], 35); -### `_.tap(value, interceptor)` +### `_.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] @@ -1789,7 +1787,7 @@ _.chain([1,2,3,200]) -### `_.template(text, data, settings)` +### `_.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] @@ -1844,7 +1842,7 @@ _.template('<%= data.hasWith %>', { 'hasWith': 'no' }, { 'variable': 'data' }); -### `_.throttle(func, wait)` +### `_.throttle(func, wait)` Creates a new function that, when invoked, will only call the original function at most once per every `wait` milliseconds. [▲][1] @@ -1866,7 +1864,7 @@ jQuery(window).on('scroll', throttled); -### `_.times(n, callback [, thisArg])` +### `_.times(n, callback [, thisArg])` Executes the `callback` function `n` times. [▲][1] @@ -1885,7 +1883,7 @@ _.times(3, function() { genie.grantWish(); }); -### `_.toArray(collection)` +### `_.toArray(collection)` Converts the `collection`, into an array. Useful for converting the `arguments` object. [▲][1] @@ -1906,7 +1904,7 @@ Converts the `collection`, into an array. Useful for converting the `arguments` -### `_.union([array1, array2, ...])` +### `_.union([array1, array2, ...])` Computes the union of the passed-in arrays. [▲][1] @@ -1927,7 +1925,7 @@ _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]); -### `_.uniq(array [, isSorted=false, callback])` +### `_.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] @@ -1950,7 +1948,7 @@ _.uniq([1, 2, 1, 3, 1, 4]); -### `_.uniqueId([prefix])` +### `_.uniqueId([prefix])` Generates a unique id. If `prefix` is passed, the id will be appended to it. [▲][1] @@ -1971,7 +1969,7 @@ _.uniqueId('contact_'); -### `_.values(object)` +### `_.values(object)` Produces an array of the `object`'s enumerable own property values. [▲][1] @@ -1992,7 +1990,7 @@ _.values({ 'one': 1, 'two': 2, 'three': 3 }); -### `_.without(array [, value1, value2, ...])` +### `_.without(array [, value1, value2, ...])` Produces a new array with all occurrences of the values removed using strict equality for comparisons, i.e. `===`. [▲][1] @@ -2014,7 +2012,7 @@ _.without([1, 2, 1, 0, 3, 1, 4], 0, 1); -### `_.wrap(func, wrapper [, arg1, arg2, ...])` +### `_.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] @@ -2041,7 +2039,7 @@ hello(); -### `_.zip([array1, array2, ...])` +### `_.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] @@ -2066,13 +2064,13 @@ _.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]); ## `_.prototype` -### `_(value)` +### `_(value)` The Lodash function. [▲][1] -### `_#chain()` +### `_#chain()` Extracts the value from a wrapped chainable object. [▲][1] @@ -2090,7 +2088,7 @@ _([1, 2, 3]).value(); -### `_#value()` +### `_#value()` Extracts the value from a wrapped chainable object. [▲][1] @@ -2115,7 +2113,7 @@ _([1, 2, 3]).value(); -### `_.templateSettings` +### `_.templateSettings` *(Object)*: By default, Lodash uses ERB-style template delimiters, change the following template settings to use alternative delimiters. [▲][1] diff --git a/lodash.js b/lodash.js index 160d25e12..1eccd01dc 100644 --- a/lodash.js +++ b/lodash.js @@ -74,9 +74,8 @@ * * @name _ * @constructor - * @param {Mixed} value The value to wrap in a chainable `lowdash` object. + * @param {Mixed} value The value to wrap in a chainable `lodash` object. * @returns {Object} Returns a `lodash` instance. - * @example */ function lodash(value) { // allow invoking `lodash` without the `new` operator @@ -90,7 +89,6 @@ * @private * @constructor * @param {Mixed} value The value to wrap in a chainable `lodash` object. - * @example */ function Wrapper(collection) { this._wrapped = collection; @@ -99,133 +97,90 @@ /*--------------------------------------------------------------------------*/ /** - * Internal recursive comparison function + * A simple iteration function. * * @private - * @param {Mixed} a A value. - * @param {Mixed} b Another value. - * @param {Array} stack Holds seen objects to avoid circular references. - * @example + * @param {Array} array The array or array-like-object to iterate over. + * @param {Function} callback The function called per iteration. + * @param {Number} [start=0] The index to start the iterating. */ - 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); + function _each(array, callback, start) { + for (var index = start || 0, length = array.length; index < length; index++) { + callback(array[index], index, array); } + }; - // 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); + /** + * Compiles iteration functions. + * + * @private + * @param {Object} options The compile options object. + * @returns {Function} Returns the compiled function. + */ + function iterationFactory(options) { + var args = options.args || (options.args = 'collection,callback,thisArg'), + array = {}, + arrayBranch = options.array !== false, + object = {}, + objectBranch = options.object !== false, + beforeLoop = options.beforeLoop || '', + breaker = options.breaker, + defaultInLoop = 'callback(collection[index],index,collection)', + inLoop = options.inLoop || ''; - 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; - } - } - } + if (typeof beforeLoop == 'string') { + array.beforeLoop = object.beforeLoop = beforeLoop; } 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; - } + array.beforeLoop = beforeLoop.array; + object.beforeLoop = beforeLoop.object; } - // remove the first collection from the stack of traversed objects - stack.pop(); - return result; + if (typeof inLoop == 'string') { + array.inLoop = object.inLoop = inLoop || defaultInLoop; + } else { + array.inLoop = inLoop.array || defaultInLoop; + object.inLoop = inLoop.object || defaultInLoop; + } + return Function('_,bind,breaker,hasOwnProperty,identity', + 'return function(' + args + '){' + + (/\bcallback\b/.test(args) + ? 'if(!callback)callback=identity;' + + (/\bthisArg\b/.test(args) + ? 'else if(thisArg)callback=bind(callback,thisArg);' + : '' + ) + : '' + ) + + (options.top || 'var result') + ';' + + 'if(collection==null)return result;' + + 'var index=-1,length=collection.length;' + + (arrayBranch + ? ((objectBranch ? 'if(length===+length){' : '') + + (array.beforeLoop || '') + ';' + + 'while(' + (options['while'] || '++index true */ - function contains(collection, target) { - return collection == null - ? false - : some(collection, function(value) { return value === target; }); - } + var contains = iterationFactory({ + 'args': 'collection,target', + 'top': 'var result=false', + 'inLoop': 'if(collection[index]===target)return true' + }); /** * Checks if the `callback` returns truthy for **all** values of a `collection`. @@ -270,14 +225,13 @@ * _.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; - } + + var every = iterationFactory({ + 'breaker': true, + 'top': 'var result=true', + 'inLoop': '!(result=result&&callback(collection[index],index,collection))&&breaker', + 'returns': '!!result' + }); /** * Examines each value in a `collection`, returning an array of all values the @@ -298,14 +252,10 @@ * 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; - } + var filter = iterationFactory({ + 'top': 'var result=[]', + 'inLoop': 'callback(collection[index],index,collection)&&(result[result.length]=collection[index])' + }); /** * Examines each value in a `collection`, returning the first one the `callback` @@ -327,16 +277,10 @@ * 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; - } + var find = iterationFactory({ + 'breaker': true, + 'inLoop': 'callback(collection[index],index,collection)?(result=collection[index],breaker):0' + }); /** * Iterates over a `collection`, executing the `callback` for each value in the @@ -354,32 +298,17 @@ * @returns {Array|Object} Returns the `collection`. * @example * - * _.forforEach([1, 2, 3], function(num) { alert(num); }); + * _.forEach([1, 2, 3], function(num) { alert(num); }); * // => alerts each number in turn... * - * _.forforEach({ 'one': 1, 'two': 2, 'three': 3}, function(num) { alert(num); }); + * _.forEach({ '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; - } + var forEach = iterationFactory({ + 'breaker': true, + 'top': 'var result=collection', + 'returns': 'collection' + }); /** * Splits a `collection` into sets, grouped by the result of running each value @@ -463,17 +392,13 @@ * _.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; + var map = iterationFactory({ + 'top': 'var result=[]', + 'inLoop': { + 'array': 'result[index]=callback(collection[index],index,collection)', + 'object': 'result[result.length]=callback(collection[index],index,collection)' } - 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, @@ -607,21 +532,11 @@ * 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 (thisArg) { - callback = bind(callback, thisArg); - } - forEach(collection, function(value, index) { - if (!initial) { - accumulator = value; - initial = true; - } else { - accumulator = callback(accumulator, value, index, collection); - } - }); - return accumulator; - } + var reduce = iterationFactory({ + 'args': 'collection,callback,result,thisArg', + 'top': 'var initial=arguments.length>2;', + 'inLoop': 'result=initial?callback(result,collection[index],index,collection):(initial=true,collection[index])' + }); /** * The right-associative version of `_.reduce`. The `callback` is bound to the @@ -644,12 +559,12 @@ * 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, - reversed = toArray(collection).reverse(); - - return initial ? reduce(reversed, callback, accumulator, thisArg) : reduce(reversed, callback); - } + var reduceRight = iterationFactory({ + 'args': 'collection,callback,result,thisArg', + 'top': 'var initial=arguments.length>2;', + 'while': 'length--', + 'inLoop': 'result=initial?callback(result,collection[length],length,collection):(initial=true,collection[length])' + }); /** * The opposite of `_.filter`, this method returns the values of a `collection` @@ -669,14 +584,10 @@ * 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; - } + var reject = iterationFactory({ + 'top': 'var result=[]', + 'inLoop': '!callback(collection[index],index,collection)&&(result[result.length]=collection[index])' + }); /** * Produces a new array of shuffled `collection` values, using a version of the @@ -787,19 +698,12 @@ * _.some([null, 0, 'yes', false]); * // => true */ - function some(collection, callback, thisArg) { - var result = false; - if (!callback) { - callback = identity; - } else if (thisArg) { - callback = bind(callback, thisArg); - } - if (collection == null) return result; - forEach(collection, function(value, index, array) { - if (result || (result = callback.call(thisArg, value, index, array))) return breaker; - }); - return !!result; - } + var some = iterationFactory({ + 'breaker': true, + 'top': 'var result=false', + 'inLoop': '(result||(result=callback(collection[index],index,collection)))&&breaker', + 'returns': '!!result' + }); /** * Uses a binary search to determine the index at which the `value` should be @@ -911,10 +815,10 @@ * @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`. + * @param {Object} [guard] Allows this method to work with others 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]); @@ -999,8 +903,8 @@ * @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`. + * @param {Object} [guard] Allows this method to work with others 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 * @@ -1044,8 +948,8 @@ * @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`. + * @param {Object} [guard] Allows this method to work with others 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 * @@ -1142,16 +1046,16 @@ * @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`. + * @param {Object} [guard] Allows this method to work with others 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); + function rest(array, n, guard) { + return slice.call(array, (n == null || guard) ? 1 : n); } /** @@ -1344,13 +1248,16 @@ * // => When the button is clicked, `this.label` will have the correct value */ function bindAll(object) { - var funcs = slice.call(arguments, 1); - if (!funcs.length) { + var funcs = arguments, + start = 1; + + if (funcs.length == 1) { + start = 0; funcs = functions(object); } - forEach(funcs, function(methodName) { + _each(funcs, function(methodName) { object[methodName] = bind(object[methodName], object); - }); + }, start); return object; } @@ -1636,11 +1543,11 @@ * // => { 'flavor': 'chocolate', 'sprinkles': 'lots' } */ function defaults(object) { - forEach(slice.call(arguments, 1), function(source) { + _each(arguments, function(source) { for (var prop in source) { if (object[prop] == null) object[prop] = source[prop]; } - }); + }, 1); return object; } @@ -1660,11 +1567,11 @@ * // => { 'name': 'moe', 'age': 40 } */ function extend(destination) { - forEach(slice.call(arguments, 1), function(source) { + _each(arguments, function(source) { for (var prop in source) { destination[prop] = source[prop]; } - }); + }, 1); return destination; } @@ -1824,7 +1731,7 @@ return true; } if (isArray(value) || isString(value)) { - return value.length === 0; + return !value.length; } for (var key in value) { if (hasOwnProperty.call(value, key)) { @@ -1841,8 +1748,8 @@ * @static * @memberOf _ * @category Objects - * @param {Mixed} value The value to compare. - * @param {Mixed} other The other value to compare. + * @param {Mixed} a The value to compare. + * @param {Mixed} b The other value to compare. * @returns {Boolean} Returns `true` if the values are equvalent, else `false`. * @example * @@ -1855,8 +1762,128 @@ * _.isEqual(moe, clone); * // => true */ - function isEqual(value, other) { - return eq(value, other, []); + function isEqual(a, b, stack) { + stack || (stack = []); + + // exit early for identical values + if (a === b) { + // treat `+0` vs. `-0` as not equal + 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 instances are equivalent; + // thus, `'5'` is quivalent to `new String('5')` + return a == String(b); + + case '[object Number]': + // treat `NaN` vs. `NaN` as equal + return a != +a + ? b != +b + // but treat `+0` vs. `-0` as not equal + : (a == 0 ? (1 / a == 1 / b) : a == +b); + + case '[object Date]': + case '[object Boolean]': + // coerce dates and booleans to numeric values, dates to milliseconds and booleans to 1 or 0; + // treat invalid dates coerced to `NaN` as not equal + 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; + } + } + + var result = true, + size = 0; + + // add the first collection to the stack of traversed objects + stack.push(a); + + // 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 && isEqual(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) && isEqual(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; } /** @@ -1879,7 +1906,7 @@ * // => false */ function isFinite(value) { - return isNumber(value) && nativeIsFinite(value); + return nativeIsFinite(value) && toString.call(value) == '[object Number]'; } /** @@ -1934,6 +1961,9 @@ * _.isNaN(NaN); * // => true * + * _.isNaN(new Number(NaN)); + * // => true + * * isNaN(undefined); * // => true * @@ -1941,8 +1971,8 @@ * // => false */ function isNaN(value) { - // `NaN` is the only value for which `===` is not reflexive. - return value !== value; + // `NaN` as a primitive is the only value that is not equal to itself + return toString.call(value) == '[object Number]' && value != +value; } /** @@ -2030,7 +2060,7 @@ * // => true */ function isUndefined(value) { - return value === void 0; + return value === undefined; } /** @@ -2193,7 +2223,7 @@ * // => 'Larry' */ function mixin(object) { - forEach(functions(object), function(methodName) { + _each(functions(object), function(methodName) { var func = lodash[methodName] = object[methodName]; lodash.prototype[methodName] = function() { @@ -2602,16 +2632,17 @@ /*--------------------------------------------------------------------------*/ - // Expose `wrapper.prototype` as `_.prototype` - lodash.prototype = Wrapper.prototype; + // Hookup private Wrapper's prototype + Wrapper.prototype = lodash.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(methodName) { + _each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(methodName) { var func = ArrayProto[methodName]; - Wrapper.prototype[methodName] = function() { + + lodash.prototype[methodName] = function() { var wrapped = this._wrapped; func.apply(wrapped, arguments); @@ -2620,8 +2651,7 @@ // array-like-objects even though the `length` property is set to `0`. // The `shift()` method is buggy in IE 8 compatibility mode, while `splice()` // is buggy regardless of mode in IE < 9 and buggy in compatibility mode in IE 9. - var length = wrapped.length; - if (length === 0) { + if (wrapped.length === 0) { delete wrapped[0]; } return this._chain ? lodash(wrapped).chain() : wrapped; @@ -2629,7 +2659,7 @@ }); // Add all accessor Array functions to the wrapper. - forEach(['concat', 'join', 'slice'], function(methodName) { + _each(['concat', 'join', 'slice'], function(methodName) { var func = ArrayProto[methodName]; lodash.prototype[methodName] = function() { var result = func.apply(this._wrapped, arguments);