Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Lodash 0.3.1

  • Loading branch information...
commit dd8611bd23f451329fea54802e097c24a0671a8f 1 parent 21eefe0
Irene Ros iros authored
Showing with 615 additions and 1,401 deletions.
  1. +1 −1  README.md
  2. +613 −400 lib/lodash.js
  3. +0 −999 lib/underscore.js
  4. +1 −1  package.json
2  README.md
View
@@ -25,7 +25,7 @@ The following builds do not have any of the dependencies built in. It is your ow
Dataset has the following dependencies:
-* [Underscore.js 1.3.1](http://underscorejs.org/)
+* [Lodash.js 0.3.1](http://lodash.com/)
* [Underscore.math.js (version unknown)](https://github.com/syntagmatic/underscore.math)
* [Underscore.deferred.js 0.1.2](https://github.com/wookiehangover/underscore.Deferred)
* [moment.js 1.4.0](http://momentjs.com/) (for date and time parsing)
1,013 lib/lodash.js
View
@@ -1,5 +1,5 @@
/*!
- * Lo-Dash v0.2.0 <http://lodash.com>
+ * Lo-Dash v0.3.1 <http://lodash.com>
* Copyright 2012 John-David Dalton <http://allyoucanleet.com/>
* Based on Underscore.js 1.3.3, copyright 2009-2012 Jeremy Ashkenas, DocumentCloud Inc.
* <http://documentcloud.github.com/underscore>
@@ -13,41 +13,6 @@
(typeof global == 'object' && global && global == global.global && (window = global), exports);
/**
- * Used to detect the JavaScript engine's argument length limit.
- *
- * The initial value of `argsLimit` is low enough not to cause uncatchable
- * errors in Java and avoid locking up older browsers like Safari 3.
- *
- * Some engines have a limit on the number of arguments functions can accept
- * before clipping the argument length or throwing an error.
- * https://bugs.webkit.org/show_bug.cgi?id=80797
- *
- * For example Firefox's limits have been observed to be at least:
- * Firefox 2 - 35,535
- * Firefox 3.6 - 16,777,215
- * Firefox 4-7 - 523,264
- * Firefox >= 8 - Throws error
- */
- var argsLimit = 5e4;
-
- try {
- (function() {
- argsLimit = arguments.length;
- }).apply(null, Array(argsLimit));
- } catch(e) { }
-
- /** Used to escape characters in templates */
- var escapes = {
- '\\': '\\',
- "'": "'",
- '\n': 'n',
- '\r': 'r',
- '\t': 't',
- '\u2028': 'u2028',
- '\u2029': 'u2029'
- };
-
- /**
* Detect the JScript [[DontEnum]] bug:
* In IE < 9 an objects own properties, shadowing non-enumerable ones, are
* made non-enumerable as well.
@@ -57,16 +22,6 @@
/** Used to generate unique IDs */
var idCounter = 0;
- /** Used to determine if values are of the language type Object */
- var objectTypes = {
- 'boolean': false,
- 'function': true,
- 'object': true,
- 'number': false,
- 'string': false,
- 'undefined': false
- };
-
/** Used to restore the original `_` reference in `noConflict` */
var oldDash = window._;
@@ -78,8 +33,11 @@
/** Used to match tokens in template text */
var reToken = /__token__(\d+)/g;
- /** Used to match unescaped characters in template text */
- var reUnescaped = /['\n\r\t\u2028\u2029\\]/g;
+ /** Used to match unescaped characters in HTML */
+ var reUnescapedHtml = /[&<"']/g;
+
+ /** Used to match unescaped characters in compiled string literals */
+ var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
/** Used to fix the JScript [[DontEnum]] bug */
var shadowed = [
@@ -87,12 +45,49 @@
'toLocaleString', 'toString', 'valueOf'
];
+ /** Used to make template sourceURLs easier to identify */
+ var templateCounter = 0;
+
/** Used to replace template delimiters */
var token = '__token__';
/** Used to store tokenized template text snippets */
var tokenized = [];
+ /**
+ * Used to escape characters for inclusion in HTML.
+ * The `>` and `/` characters don't require escaping in HTML and have no
+ * special meaning unless they're part of a tag or an unquoted attribute value
+ * http://mathiasbynens.be/notes/ambiguous-ampersands (semi-related fun fact)
+ */
+ var htmlEscapes = {
+ '&': '&amp;',
+ '<': '&lt;',
+ '"': '&quot;',
+ "'": '&#x27;'
+ };
+
+ /** Used to determine if values are of the language type Object */
+ var objectTypes = {
+ 'boolean': false,
+ 'function': true,
+ 'object': true,
+ 'number': false,
+ 'string': false,
+ 'undefined': false
+ };
+
+ /** Used to escape characters for inclusion in compiled string literals */
+ var stringEscapes = {
+ '\\': '\\',
+ "'": "'",
+ '\n': 'n',
+ '\r': 'r',
+ '\t': 't',
+ '\u2028': 'u2028',
+ '\u2029': 'u2029'
+ };
+
/** Object#toString result shortcuts */
var arrayClass = '[object Array]',
boolClass = '[object Boolean]',
@@ -200,7 +195,7 @@
* @memberOf _.templateSettings
* @type String
*/
- 'variable': 'object'
+ 'variable': 'obj'
};
/*--------------------------------------------------------------------------*/
@@ -223,7 +218,7 @@
// the following branch is for iterating arrays and array-like objects
'<% if (arrayBranch) { %>' +
'var length = <%= firstArg %>.length; index = -1;' +
- ' <% if (objectBranch) { %>\nif (length === +length) {<% } %>\n' +
+ ' <% if (objectBranch) { %>\nif (length === length >>> 0) {<% } %>\n' +
' <%= arrayBranch.beforeLoop %>;\n' +
' while (<%= arrayBranch.loopExp %>) {\n' +
' <%= arrayBranch.inLoop %>;\n' +
@@ -285,7 +280,7 @@
/**
* Reusable iterator options shared by
- * `every`, `filter`, `find`, `forEach`,`groupBy`, `map`, `reject`, and `some`.
+ * `every`, `filter`, `find`, `forEach`, `forIn`, `forOwn`, `map`, `reject`, and `some`.
*/
var baseIteratorOptions = {
'args': 'collection, callback, thisArg',
@@ -295,7 +290,7 @@
' callback = identity\n' +
'}\n' +
'else if (thisArg) {\n' +
- ' callback = bind(callback, thisArg)\n' +
+ ' callback = iteratorBind(callback, thisArg)\n' +
'}',
'inLoop': 'callback(collection[index], index, collection)'
};
@@ -320,23 +315,21 @@
'bottom': (hasDontEnumBug ? ' }\n' : '') + '}'
};
- /** Reusable iterator options for `filter` and `reject` */
+ /** Reusable iterator options for `filter` and `reject` */
var filterIteratorOptions = {
'init': '[]',
'inLoop': 'callback(collection[index], index, collection) && result.push(collection[index])'
};
- /** Reusable iterator options for `map`, `pluck`, and `values` */
- var mapIteratorOptions = {
- 'init': '',
- 'exit': 'if (!collection) return []',
- 'beforeLoop': {
- 'array': 'result = Array(length)',
- 'object': 'result = []'
- },
+ /** Reusable iterator options for `find`, `forEach`, `forIn`, and `forOwn` */
+ var forEachIteratorOptions = {
+ 'top': 'if (thisArg) callback = iteratorBind(callback, thisArg)'
+ };
+
+ /** Reusable iterator options for `forIn` and `forOwn` */
+ var forOwnIteratorOptions = {
'inLoop': {
- 'array': 'result[index] = callback(collection[index], index, collection)',
- 'object': 'result.push(callback(collection[index], index, collection))'
+ 'object': baseIteratorOptions.inLoop
}
};
@@ -437,13 +430,13 @@
}
// create the function factory
var factory = Function(
- 'arrayClass, bind, funcClass, hasOwnProperty, identity, objectTypes, ' +
+ 'arrayClass, funcClass, hasOwnProperty, identity, iteratorBind, objectTypes, ' +
'stringClass, toString, undefined',
'"use strict"; return function(' + args + ') {\n' + iteratorTemplate(data) + '\n}'
);
// return the compiled function
return factory(
- arrayClass, bind, funcClass, hasOwnProperty, identity, objectTypes,
+ arrayClass, funcClass, hasOwnProperty, identity, iteratorBind, objectTypes,
stringClass, toString
);
}
@@ -468,8 +461,34 @@
* @param {String} match The matched character to escape.
* @returns {String} Returns the escaped character.
*/
- function escapeChar(match) {
- return '\\' + escapes[match];
+ function escapeStringChar(match) {
+ return '\\' + stringEscapes[match];
+ }
+
+ /**
+ * Used by `escape()` to escape characters for inclusion in HTML.
+ *
+ * @private
+ * @param {String} match The matched character to escape.
+ * @returns {String} Returns the escaped character.
+ */
+ function escapeHtmlChar(match) {
+ return htmlEscapes[match];
+ }
+
+ /**
+ * Creates a new function that, when called, invokes `func` with the `this`
+ * binding of `thisArg` and the arguments (value, index, object).
+ *
+ * @private
+ * @param {Function} func The function to bind.
+ * @param {Mixed} [thisArg] The `this` binding of `func`.
+ * @returns {Function} Returns the new bound function.
+ */
+ function iteratorBind(func, thisArg) {
+ return function(value, index, object) {
+ return func.call(thisArg, value, index, object);
+ };
}
/**
@@ -482,6 +501,21 @@
}
/**
+ * A shim implementation of `Object.keys` that produces an array of the given
+ * object's own enumerable property names.
+ *
+ * @private
+ * @param {Object} object The object to inspect.
+ * @returns {Array} Returns a new array of property names.
+ */
+ var shimKeys = createIterator({
+ 'args': 'object',
+ 'exit': 'if (!objectTypes[typeof object] || object === null) throw TypeError()',
+ 'init': '[]',
+ 'inLoop': 'result.push(index)'
+ });
+
+ /**
* Used by `template()` to replace "escape" template delimiters with tokens.
*
* @private
@@ -549,15 +583,16 @@
/**
* Checks if the `callback` returns a truthy value for **all** elements of a
- * `collection`. The `callback` is invoked with 3 arguments; for arrays they
- * are (value, index, array) and for objects they are (value, key, object).
+ * `collection`. The `callback` is bound to `thisArg` and invoked with 3
+ * arguments; for arrays they are (value, index, array) and for objects they
+ * are (value, key, object).
*
* @static
* @memberOf _
* @alias all
* @category Collections
* @param {Array|Object} collection The collection to iterate over.
- * @param {Function} callback The function called per iteration.
+ * @param {Function} [callback=identity] 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
@@ -569,16 +604,16 @@
/**
* 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).
+ * `callback` returns truthy for. The `callback` is bound to `thisArg` and
+ * invoked with 3 arguments; for arrays they are (value, index, array) and for
+ * objects they are (value, key, object).
*
* @static
* @memberOf _
* @alias select
* @category Collections
* @param {Array|Object} collection The collection to iterate over.
- * @param {Function} callback The function called per iteration.
+ * @param {Function} [callback=identity] 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
@@ -592,8 +627,8 @@
* 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).
+ * bound to `thisArg` and invoked with 3 arguments; for arrays they are
+ * (value, index, array) and for objects they are (value, key, object).
*
* @static
* @memberOf _
@@ -608,15 +643,16 @@
* var even = _.find([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; });
* // => 2
*/
- var find = createIterator(baseIteratorOptions, {
+ var find = createIterator(baseIteratorOptions, forEachIteratorOptions, {
+ 'init': '',
'inLoop': 'if (callback(collection[index], index, collection)) return collection[index]'
});
/**
* 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).
+ * `collection`. The `callback` is bound to `thisArg` and invoked with 3
+ * arguments; for arrays they are (value, index, array) and for objects they
+ * are (value, key, object).
*
* @static
* @memberOf _
@@ -628,28 +664,26 @@
* @returns {Array|Object} Returns the `collection`.
* @example
*
- * _.forEach({ 'one': 1, 'two': 2, 'three': 3}, function(num) { alert(num); });
- * // => alerts each number in turn
+ * _([1, 2, 3]).forEach(alert).join(',');
+ * // => alerts each number and returns '1,2,3'
*
- * _([1, 2, 3]).forEach(function(num) { alert(num); }).join(',');
- * // => alerts each number in turn and returns '1,2,3'
+ * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, alert);
+ * // => alerts each number (order is not guaranteed)
*/
- var forEach = createIterator(baseIteratorOptions, {
- 'top': 'if (thisArg) callback = bind(callback, thisArg)'
- });
+ var forEach = createIterator(baseIteratorOptions, forEachIteratorOptions);
/**
* 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).
+ * through a transformation `callback`. The `callback` is bound to `thisArg`
+ * and invoked with 3 arguments; for arrays they are (value, index, array)
+ * and for objects they are (value, key, object).
*
* @static
* @memberOf _
* @alias collect
* @category Collections
* @param {Array|Object} collection The collection to iterate over.
- * @param {Function} callback The function called per iteration.
+ * @param {Function} [callback=identity] 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
@@ -658,45 +692,27 @@
* // => [3, 6, 9]
*
* _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; });
- * // => [3, 6, 9]
+ * // => [3, 6, 9] (order is not guaranteed)
*/
- var map = createIterator(baseIteratorOptions, mapIteratorOptions);
-
- /**
- * 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']
- */
- var pluck = createIterator(mapIteratorOptions, {
- 'args': 'collection, property',
+ var map = createIterator(baseIteratorOptions, {
+ 'init': '',
+ 'exit': 'if (!collection) return []',
+ 'beforeLoop': {
+ 'array': 'result = Array(length)',
+ 'object': 'result = []'
+ },
'inLoop': {
- 'array': 'result[index] = collection[index][property]',
- 'object': 'result.push(collection[index][property])'
+ 'array': 'result[index] = callback(collection[index], index, collection)',
+ 'object': 'result.push(callback(collection[index], index, collection))'
}
});
/**
* 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).
+ * by the `callback`. The `callback` is bound to `thisArg` and invoked with 4
+ * arguments; for arrays they are (accumulator, value, index, array) and for
+ * objects they are (accumulator, value, key, object).
*
* @static
* @memberOf _
@@ -717,7 +733,7 @@
'init': 'accumulator',
'top':
'var noaccum = arguments.length < 3;\n' +
- 'if (thisArg) callback = bind(callback, thisArg)',
+ 'if (thisArg) callback = iteratorBind(callback, thisArg)',
'beforeLoop': {
'array': 'if (noaccum) result = collection[++index]'
},
@@ -732,10 +748,7 @@
});
/**
- * The right-associative version of `_.reduce`. The `callback` is bound to the
- * `thisArg` value, if one is passed. The `callback` is invoked with 4 arguments;
- * for arrays they are (accumulator, value, index, array) and for objects they
- * are (accumulator, value, key, object).
+ * The right-associative version of `_.reduce`.
*
* @static
* @memberOf _
@@ -761,9 +774,9 @@
noaccum = arguments.length < 3;
if(thisArg) {
- callback = bind(callback, thisArg);
+ callback = iteratorBind(callback, thisArg);
}
- if (length === +length) {
+ if (length === length >>> 0) {
if (length && noaccum) {
accumulator = collection[--length];
}
@@ -789,15 +802,13 @@
/**
* 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).
+ * that `callback` does **not** return truthy for.
*
* @static
* @memberOf _
* @category Collections
* @param {Array|Object} collection The collection to iterate over.
- * @param {Function} callback The function called per iteration.
+ * @param {Function} [callback=identity] 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
@@ -812,16 +823,16 @@
/**
* Checks if the `callback` returns a truthy value for **any** element of a
* `collection`. The function returns as soon as it finds passing value, and
- * does not iterate over the entire `collection`. The `callback` is invoked
- * with 3 arguments; for arrays they are (value, index, array) and for objects
- * they are (value, key, object).
+ * does not iterate over the entire `collection`. The `callback` is bound to
+ * `thisArg` and invoked with 3 arguments; for arrays they are
+ * (value, index, array) and for objects they are (value, key, object).
*
* @static
* @memberOf _
* @alias any
* @category Collections
* @param {Array|Object} collection The collection to iterate over.
- * @param {Function} callback The function called per iteration.
+ * @param {Function} [callback=identity] 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
@@ -856,34 +867,12 @@
return collection.toArray();
}
var length = collection.length;
- if (length === +length) {
+ if (length === length >>> 0) {
return slice.call(collection);
}
return values(collection);
}
- /**
- * Produces an array of enumerable own property values of the `collection`.
- *
- * @static
- * @memberOf _
- * @alias methods
- * @category Collections
- * @param {Array|Object} collection The collection to inspect.
- * @returns {Array} Returns a new array of property values.
- * @example
- *
- * _.values({ 'one': 1, 'two': 2, 'three': 3 });
- * // => [1, 2, 3]
- */
- var values = createIterator(mapIteratorOptions, {
- 'args': 'collection',
- 'inLoop': {
- 'array': 'result[index] = collection[index]',
- 'object': 'result.push(collection[index])'
- }
- });
-
/*--------------------------------------------------------------------------*/
/**
@@ -901,9 +890,12 @@
* // => [1, 2, 3]
*/
function compact(array) {
+ var result = [];
+ if (!array) {
+ return result;
+ }
var index = -1,
- length = array.length,
- result = [];
+ length = array.length;
while (++index < length) {
if (array[index]) {
@@ -930,9 +922,12 @@
* // => [1, 3, 4]
*/
function difference(array) {
+ var result = [];
+ if (!array) {
+ return result;
+ }
var index = -1,
length = array.length,
- result = [],
flattened = concat.apply(result, slice.call(arguments, 1));
while (++index < length) {
@@ -956,14 +951,16 @@
* @param {Object} [guard] Internally used to allow 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`.
+ * of `array`.
* @example
*
* _.first([5, 4, 3, 2, 1]);
* // => 5
*/
function first(array, n, guard) {
- return (n == undefined || guard) ? array[0] : slice.call(array, 0, n);
+ if (array) {
+ return (n == undefined || guard) ? array[0] : slice.call(array, 0, n);
+ }
}
/**
@@ -985,10 +982,13 @@
* // => [1, 2, 3, [[4]]];
*/
function flatten(array, shallow) {
+ var result = [];
+ if (!array) {
+ return result;
+ }
var value,
index = -1,
- length = array.length,
- result = [];
+ length = array.length;
while (++index < length) {
value = array[index];
@@ -1002,10 +1002,10 @@
}
/**
- * Splits a `collection` into sets, grouped by the result of running each value
- * through `callback`. The `callback` is invoked with 3 arguments;
- * (value, index, array). The `callback` argument may also be the name of a
- * property to group by.
+ * Splits `array` into sets, grouped by the result of running each value
+ * through `callback`. The `callback` is bound to `thisArg` and invoked with 3
+ * arguments; (value, index, array). The `callback` argument may also be the
+ * name of a property to group by.
*
* @static
* @memberOf _
@@ -1027,71 +1027,25 @@
* // => { '3': ['one', 'two'], '5': ['three'] }
*/
function groupBy(array, callback, thisArg) {
+ var result = {};
+ if (!array) {
+ return result;
+ }
var prop,
value,
index = -1,
- isFunc = toString.call(callback) == funcClass,
- length = array.length,
- result = {};
+ isFunc = typeof callback == 'function',
+ length = array.length;
if (isFunc && thisArg) {
- callback = bind(callback, thisArg);
+ callback = iteratorBind(callback, thisArg);
}
while (++index < length) {
value = array[index];
prop = isFunc ? callback(value, index, array) : value[callback];
(hasOwnProperty.call(result, prop) ? result[prop] : result[prop] = []).push(value);
}
- return result
- }
-
- /**
- * 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 Arrays
- * @param {Array} array The array 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]
- *
- * _.sortBy([1, 2, 3, 4, 5, 6], function(num) { return this.sin(num); }, Math);
- * // => [5, 4, 6, 3, 1, 2]
- */
- function sortBy(array, callback, thisArg) {
- if (toString.call(callback) != funcClass) {
- var prop = callback;
- callback = function(array) { return array[prop]; };
- } else if (thisArg) {
- callback = bind(callback, thisArg);
- }
- return pluck(map(array, function(value, index) {
- return {
- 'criteria': callback(value, index, array),
- 'value': value
- };
- }).sort(function(left, right) {
- var a = left.criteria,
- b = right.criteria;
-
- if (a === undefined) {
- return 1;
- }
- if (b === undefined) {
- return -1;
- }
- return a < b ? -1 : a > b ? 1 : 0;
- }), 'value');
+ return result;
}
/**
@@ -1104,23 +1058,36 @@
* @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.
+ * @param {Boolean|Number} [fromIndex=0] The index to start searching from or
+ * `true` to perform a binary search on a sorted `array`.
* @returns {Number} Returns the index of the matched value or `-1`.
* @example
*
- * _.indexOf([1, 2, 3], 2);
+ * _.indexOf([1, 2, 3, 1, 2, 3], 2);
* // => 1
+ *
+ * _.indexOf([1, 2, 3, 1, 2, 3], 2, 3);
+ * // => 4
+ *
+ * _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
+ * // => 2
*/
- function indexOf(array, value, isSorted) {
- var index, length;
+ function indexOf(array, value, fromIndex) {
if (!array) {
return -1;
}
- if (isSorted) {
- index = sortedIndex(array, value);
- return array[index] === value ? index : -1;
+ var index = -1,
+ length = array.length;
+
+ if (fromIndex) {
+ if (typeof fromIndex == 'number') {
+ index = (fromIndex < 0 ? Math.max(0, length + fromIndex) : fromIndex) - 1;
+ } else {
+ index = sortedIndex(array, value);
+ return array[index] === value ? index : -1;
+ }
}
- for (index = 0, length = array.length; index < length; index++) {
+ while (++index < length) {
if (array[index] === value) {
return index;
}
@@ -1129,7 +1096,7 @@
}
/**
- * Gets all but the last value of the `array`. Pass `n` to exclude the last `n`
+ * Gets all but the last value of `array`. Pass `n` to exclude the last `n`
* values from the result.
*
* @static
@@ -1139,13 +1106,16 @@
* @param {Number} [n] The number of elements to return.
* @param {Object} [guard] Internally used to allow 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`.
+ * @returns {Array} Returns all but the last value or `n` values of `array`.
* @example
*
- * _.initial([5, 4, 3, 2, 1]);
- * // => [5, 4, 3, 2]
+ * _.initial([3, 2, 1]);
+ * // => [3, 2]
*/
function initial(array, n, guard) {
+ if (!array) {
+ return [];
+ }
return slice.call(array, 0, -((n == undefined || guard) ? 1 : n));
}
@@ -1154,7 +1124,6 @@
*
* @static
* @memberOf _
- * @alias intersect
* @category Arrays
* @param {Array} [array1, array2, ...] Arrays to process.
* @returns {Array} Returns a new array of unique values, in order, that are
@@ -1165,11 +1134,14 @@
* // => [1, 2]
*/
function intersection(array) {
+ var result = [];
+ if (!array) {
+ return result;
+ }
var value,
index = -1,
length = array.length,
- others = slice.call(arguments, 1),
- result = [];
+ others = slice.call(arguments, 1);
while (++index < length) {
value = array[index];
@@ -1182,27 +1154,36 @@
}
/**
- * Calls the method named by `methodName` for each value of the `collection`.
- * Additional arguments will be passed to each invoked method.
+ * Invokes the method named by `methodName` on each element of `array`.
+ * Additional arguments will be passed to each invoked method. If `methodName`
+ * is a function it will be invoked for, and `this` bound to, each element
+ * of `array`.
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to iterate over.
- * @param {String} methodName The name of the method to invoke.
+ * @param {Function|String} methodName The name of the method to invoke or
+ * the function invoked per iteration.
* @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]]
+ *
+ * _.invoke([123, 456], String.prototype.split, '');
+ * // => [['1', '2', '3'], ['4', '5', '6']]
*/
function invoke(array, methodName) {
+ var result = [];
+ if (!array) {
+ return result;
+ }
var args = slice.call(arguments, 2),
index = -1,
length = array.length,
- isFunc = toString.call(methodName) == funcClass,
- result = [];
+ isFunc = typeof methodName == 'function';
while (++index < length) {
result[index] = (isFunc ? methodName : array[index][methodName]).apply(array[index], args);
@@ -1221,15 +1202,18 @@
* @param {Number} [n] The number of elements to return.
* @param {Object} [guard] Internally used to allow 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`.
+ * @returns {Mixed} Returns the last value or an array of the last `n` values
+ * of `array`.
* @example
*
- * _.last([5, 4, 3, 2, 1]);
+ * _.last([3, 2, 1]);
* // => 1
*/
function last(array, n, guard) {
- var length = array.length;
- return (n == undefined || guard) ? array[length - 1] : slice.call(array, -n || length);
+ if (array) {
+ var length = array.length;
+ return (n == undefined || guard) ? array[length - 1] : slice.call(array, -n || length);
+ }
}
/**
@@ -1241,17 +1225,24 @@
* @category Arrays
* @param {Array} array The array to search.
* @param {Mixed} value The value to search for.
+ * @param {Number} [fromIndex=array.length-1] The index to start searching from.
* @returns {Number} Returns the index of the matched value or `-1`.
* @example
*
* _.lastIndexOf([1, 2, 3, 1, 2, 3], 2);
* // => 4
+ *
+ * _.lastIndexOf([1, 2, 3, 1, 2, 3], 2, 3);
+ * // => 1
*/
- function lastIndexOf(array, value) {
+ function lastIndexOf(array, value, fromIndex) {
if (!array) {
return -1;
}
var index = array.length;
+ if (fromIndex && typeof fromIndex == 'number') {
+ index = (fromIndex < 0 ? Math.max(0, index + fromIndex) : Math.min(fromIndex, index - 1)) + 1;
+ }
while (index--) {
if (array[index] === value) {
return index;
@@ -1263,8 +1254,8 @@
/**
* Retrieves the maximum value of an `array`. If `callback` is passed,
* it will be executed for each value in the `array` to generate the
- * criterion by which the value is ranked. The `callback` is invoked with 3
- * arguments; (value, index, array).
+ * criterion by which the value is ranked. The `callback` is bound to
+ * `thisArg` and invoked with 3 arguments; (value, index, array).
*
* @static
* @memberOf _
@@ -1285,29 +1276,29 @@
* // => { 'name': 'curly', 'age': 60 };
*/
function max(array, callback, thisArg) {
+ var computed = -Infinity,
+ result = computed;
+
+ if (!array) {
+ return result;
+ }
var current,
- computed = -Infinity,
index = -1,
- length = array.length,
- result = computed;
+ length = array.length;
if (!callback) {
- // fast path for arrays of numbers
- if (array[0] === +array[0] && length <= argsLimit) {
- // some JavaScript engines have a limit on the number of arguments functions
- // can accept before clipping the argument length or throwing an error
- try {
- return Math.max.apply(Math, array);
- } catch(e) { }
- }
- if (!array.length) {
- return result;
+ while (++index < length) {
+ if (array[index] > result) {
+ result = array[index];
+ }
}
- } else if (thisArg) {
- callback = bind(callback, thisArg);
+ return result;
+ }
+ if (thisArg) {
+ callback = iteratorBind(callback, thisArg);
}
while (++index < length) {
- current = callback ? callback(array[index], index, array) : array[index];
+ current = callback(array[index], index, array);
if (current > computed) {
computed = current;
result = array[index];
@@ -1319,8 +1310,8 @@
/**
* Retrieves the minimum value of an `array`. If `callback` is passed,
* it will be executed for each value in the `array` to generate the
- * criterion by which the value is ranked. The `callback` is invoked with 3
- * arguments; (value, index, array).
+ * criterion by which the value is ranked. The `callback` is bound to `thisArg`
+ * and invoked with 3 arguments; (value, index, array).
*
* @static
* @memberOf _
@@ -1335,26 +1326,29 @@
* // => 2
*/
function min(array, callback, thisArg) {
+ var computed = Infinity,
+ result = computed;
+
+ if (!array) {
+ return result;
+ }
var current,
- computed = Infinity,
index = -1,
- length = array.length,
- result = computed;
+ length = array.length;
if (!callback) {
- if (array[0] === +array[0] && length <= argsLimit) {
- try {
- return Math.min.apply(Math, array);
- } catch(e) { }
- }
- if (!array.length) {
- return result;
+ while (++index < length) {
+ if (array[index] < result) {
+ result = array[index];
+ }
}
- } else if (thisArg) {
- callback = bind(callback, thisArg);
+ return result;
+ }
+ if (thisArg) {
+ callback = iteratorBind(callback, thisArg);
}
while (++index < length) {
- current = callback ? callback(array[index], index, array) : array[index];
+ current = callback(array[index], index, array);
if (current < computed) {
computed = current;
result = array[index];
@@ -1364,6 +1358,40 @@
}
/**
+ * Retrieves the value of a specified property from all elements in `array`.
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {Array} array The array 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(array, property) {
+ if (!array) {
+ return [];
+ }
+ var index = -1,
+ length = array.length,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = array[index][property];
+ }
+ return result;
+ }
+
+ /**
* 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.
@@ -1412,7 +1440,7 @@
/**
* 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.
+ * `array`. Pass `n` to exclude the first `n` values from the result.
*
* @static
* @memberOf _
@@ -1422,13 +1450,16 @@
* @param {Number} [n] The number of elements to return.
* @param {Object} [guard] Internally used to allow 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`.
+ * @returns {Array} Returns all but the first value or `n` values of `array`.
* @example
*
- * _.rest([5, 4, 3, 2, 1]);
- * // => [4, 3, 2, 1]
+ * _.rest([3, 2, 1]);
+ * // => [2, 1]
*/
function rest(array, n, guard) {
+ if (!array) {
+ return [];
+ }
return slice.call(array, (n == undefined || guard) ? 1 : n);
}
@@ -1447,6 +1478,9 @@
* // => [4, 1, 6, 3, 5, 2]
*/
function shuffle(array) {
+ if (!array) {
+ return [];
+ }
var rand,
index = -1,
length = array.length,
@@ -1461,39 +1495,122 @@
}
/**
- * Uses a binary search to determine the smallest index at which the `value`
- * should be inserted into the `collection` in order to maintain the sort order
- * of the `collection`. If `callback` is passed, it will be executed for each
- * value in the `collection` to compute their sort ranking. The `callback` is
- * invoked with 1 argument; (value).
+ * Produces a new sorted array, ranked in ascending order by the results of
+ * running each element of `array` through `callback`. The `callback` is
+ * bound to `thisArg` and invoked with 3 arguments; (value, index, array). The
+ * `callback` argument may also be the name of a property to sort by (e.g. 'length').
+ *
+ * @static
+ * @memberOf _
+ * @category Arrays
+ * @param {Array} array The array 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], function(num) { return Math.sin(num); });
+ * // => [3, 1, 2]
+ *
+ * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math);
+ * // => [3, 1, 2]
+ *
+ * _.sortBy(['larry', 'brendan', 'moe'], 'length');
+ * // => ['moe', 'larry', 'brendan']
+ */
+ function sortBy(array, callback, thisArg) {
+ if (!array) {
+ return [];
+ }
+ if (typeof callback == 'string') {
+ var prop = callback;
+ callback = function(array) { return array[prop]; };
+ } else if (thisArg) {
+ callback = iteratorBind(callback, thisArg);
+ }
+ var index = -1,
+ length = array.length,
+ result = Array(length);
+
+ while (++index < length) {
+ result[index] = {
+ 'criteria': callback(array[index], index, array),
+ 'value': array[index]
+ };
+ }
+ result.sort(function(left, right) {
+ var a = left.criteria,
+ b = right.criteria;
+
+ if (a === undefined) {
+ return 1;
+ }
+ if (b === undefined) {
+ return -1;
+ }
+ return a < b ? -1 : a > b ? 1 : 0;
+ });
+
+ while (length--) {
+ result[length] = result[length].value;
+ }
+ return result;
+ }
+
+ /**
+ * Uses a binary search to determine the smallest index at which the `value`
+ * should be inserted into `array` in order to maintain the sort order of the
+ * sorted `array`. If `callback` is passed, it will be executed for `value` and
+ * each element in `array` to compute their sort ranking. The `callback` is
+ * bound to `thisArg` and invoked with 1 argument; (value).
*
* @static
* @memberOf _
* @category Arrays
* @param {Array} array The array to iterate over.
* @param {Mixed} value The value to evaluate.
- * @param {Function} [callback] The function called per iteration.
+ * @param {Function} [callback=identity] The function called per iteration.
+ * @param {Mixed} [thisArg] The `this` binding for the callback.
* @returns {Number} Returns the index at which the value should be inserted
- * into the collection.
+ * into `array`.
* @example
*
- * _.sortedIndex([10, 20, 30, 40, 50], 35);
- * // => 3
+ * _.sortedIndex([20, 30, 40], 35);
+ * // => 2
+ *
+ * var dict = {
+ * 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'thirty-five': 35, 'fourty': 40 }
+ * };
+ *
+ * _.sortedIndex(['twenty', 'thirty', 'fourty'], 'thirty-five', function(word) {
+ * return dict.wordToNumber[word];
+ * });
+ * // => 2
+ *
+ * _.sortedIndex(['twenty', 'thirty', 'fourty'], 'thirty-five', function(word) {
+ * return this.wordToNumber[word];
+ * }, dict);
+ * // => 2
*/
- function sortedIndex(array, value, callback) {
+ function sortedIndex(array, value, callback, thisArg) {
+ if (!array) {
+ return 0;
+ }
var mid,
low = 0,
high = array.length;
if (callback) {
- value = callback(value);
- }
- while (low < high) {
- mid = (low + high) >> 1;
- if ((callback ? callback(array[mid]) : array[mid]) < value) {
- low = mid + 1;
- } else {
- high = mid;
+ value = callback.call(thisArg, value);
+ while (low < high) {
+ mid = (low + high) >>> 1;
+ callback.call(thisArg, array[mid]) < value ? low = mid + 1 : high = mid;
+ }
+ } else {
+ while (low < high) {
+ mid = (low + high) >>> 1;
+ array[mid] < value ? low = mid + 1 : high = mid;
}
}
return low;
@@ -1532,8 +1649,8 @@
* 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).
+ * uniqueness is computed. The `callback` is bound to `thisArg` and invoked
+ * with 3 arguments; (value, index, array).
*
* @static
* @memberOf _
@@ -1541,25 +1658,46 @@
* @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
+ * @param {Function} [callback=identity] The function called per iteration.
+ * @param {Mixed} [thisArg] The `this` binding for the callback.
* @returns {Array} Returns a duplicate-value-free array.
* @example
*
- * _.uniq([1, 2, 1, 3, 1, 4]);
- * // => [1, 2, 3, 4]
+ * _.uniq([1, 2, 1, 3, 1]);
+ * // => [1, 2, 3]
+ *
+ * _.uiq([1, 1, 2, 2, 3], true);
+ * // => [1, 2, 3]
+ *
+ * _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return Math.floor(num); });
+ * // => [1, 2, 3]
+ *
+ * _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return this.floor(num); }, Math);
+ * // => [1, 2, 3]
*/
- function uniq(array, isSorted, callback) {
+ function uniq(array, isSorted, callback, thisArg) {
+ var result = [];
+ if (!array) {
+ return result;
+ }
var computed,
index = -1,
length = array.length,
- result = [],
seen = [];
- if (length < 3) {
- isSorted = true;
+ // juggle arguments
+ if (typeof isSorted == 'function') {
+ thisArg = callback;
+ callback = isSorted;
+ isSorted = false;
+ }
+ if (!callback) {
+ callback = identity;
+ } else if (thisArg) {
+ callback = iteratorBind(callback, thisArg);
}
while (++index < length) {
- computed = callback ? callback(array[index]) : array[index];
+ computed = callback(array[index], index, array);
if (isSorted
? !index || seen[seen.length - 1] !== computed
: indexOf(seen, computed) < 0
@@ -1587,10 +1725,13 @@
* // => [2, 3, 4]
*/
function without(array) {
+ var result = [];
+ if (!array) {
+ return result;
+ }
var excluded = slice.call(arguments, 1),
index = -1,
- length = array.length,
- result = [];
+ length = array.length;
while (++index < length) {
if (indexOf(excluded, array[index]) < 0) {
@@ -1616,7 +1757,10 @@
* _.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]);
* // => [['moe', 30, true], ['larry', 40, false], ['curly', 50, false]]
*/
- function zip() {
+ function zip(array) {
+ if (!array) {
+ return [];
+ }
var index = -1,
length = max(pluck(arguments, 'length')),
result = Array(length);
@@ -1646,7 +1790,7 @@
* _.forEach(notes, function(note) {
* note.asyncSave({ 'success': renderNotes });
* });
- * // renderNotes is run once, after all notes have saved.
+ * // `renderNotes` is run once, after all notes have saved
*/
function after(n, func) {
if (n < 1) {
@@ -1669,13 +1813,16 @@
* @memberOf _
* @category Functions
* @param {Function|Object} func The function to bind or the object the method belongs to.
- * @param @param {Mixed} [thisArg] The `this` binding of `func` or the method name.
+ * @param {Mixed} [thisArg] The `this` binding of `func` or the method name.
* @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied.
* @returns {Function} Returns the new bound function.
* @example
*
* // basic bind
- * var func = function(greeting) { return greeting + ': ' + this.name; };
+ * var func = function(greeting) {
+ * return greeting + ': ' + this.name;
+ * };
+ *
* func = _.bind(func, { 'name': 'moe' }, 'hi');
* func();
* // => 'hi: moe'
@@ -1693,11 +1840,11 @@
* // => 'hi: moe'
*
* object.greet = function(greeting) {
- * return greeting + ' ' + this.name + '!';
+ * return greeting + ', ' + this.name + '!';
* };
*
* func();
- * // => 'hi moe!'
+ * // => 'hi, moe!'
*/
function bind(func, thisArg) {
var methodName,
@@ -1712,52 +1859,44 @@
else if (nativeBind) {
return nativeBind.call.apply(nativeBind, arguments);
}
- // `Function#bind` spec
- // http://es5.github.com/#x15.3.4.5
- var partialArgs = slice.call(arguments, 2),
- partialArgsLength = partialArgs.length;
+
+ var partialArgs = slice.call(arguments, 2);
function bound() {
+ // `Function#bind` spec
+ // http://es5.github.com/#x15.3.4.5
var args = arguments,
thisBinding = thisArg;
if (!isFunc) {
func = thisArg[methodName];
}
- if (partialArgsLength) {
- if (args.length) {
- partialArgs.length = partialArgsLength;
- push.apply(partialArgs, args);
- }
- args = partialArgs;
+ if (partialArgs.length) {
+ args = args.length
+ ? concat.apply(partialArgs, args)
+ : partialArgs;
}
-
- var isInstance = this instanceof bound;
- if (isInstance) {
+ if (this instanceof bound) {
// get `func` instance if `bound` is invoked in a `new` expression
noop.prototype = func.prototype;
thisBinding = new noop;
- }
-
- var result = args.length ? func.apply(thisBinding, args) : func.call(thisBinding);
- partialArgs.length = partialArgsLength;
- if (isInstance) {
// mimic the constructor's `return` behavior
// http://es5.github.com/#x13.2.2
+ var result = func.apply(thisBinding, args);
return objectTypes[typeof result] && result !== null
? result
: thisBinding
}
- return result;
+ return func.apply(thisBinding, args);
}
return bound;
}
/**
- * 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`
+ * Binds methods on `object` to `object`, overwriting the existing method.
+ * If no method names are provided, all the function properties of `object`
* will be bound.
*
* @static
@@ -1795,7 +1934,7 @@
/**
* 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()))`.
+ * In math terms, composing the functions `f()`, `g()`, and `h()` produces `f(g(h()))`.
*
* @static
* @memberOf _
@@ -1906,7 +2045,7 @@
* @example
*
* _.defer(function() { alert('deferred'); });
- * // Returns from the function before the alert runs.
+ * // returns from the function before `alert` is called
*/
function defer(func) {
var args = slice.call(arguments, 1);
@@ -2124,8 +2263,8 @@
* @example
*
* var iceCream = { 'flavor': 'chocolate' };
- * _.defaults(iceCream, { 'flavor': 'vanilla', 'sprinkles': 'lots' });
- * // => { 'flavor': 'chocolate', 'sprinkles': 'lots' }
+ * _.defaults(iceCream, { 'flavor': 'vanilla', 'sprinkles': 'rainbow' });
+ * // => { 'flavor': 'chocolate', 'sprinkles': 'rainbow' }
*/
var defaults = createIterator(extendIteratorOptions, {
'inLoop': 'if (object[index] == undefined)' + extendIteratorOptions.inLoop
@@ -2149,8 +2288,60 @@
var extend = createIterator(extendIteratorOptions);
/**
- * Produces a sorted array of the properties, own and inherited, of `object`
- * that have function values.
+ * Iterates over `object`'s own and inherited enumerable properties, executing
+ * the `callback` for each property. The `callback` is bound to `thisArg` and
+ * invoked with 3 arguments; (value, key, object).
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Object} object The object to iterate over.
+ * @param {Function} callback The function called per iteration.
+ * @param {Mixed} [thisArg] The `this` binding for the callback.
+ * @returns {Object} Returns the `object`.
+ * @example
+ *
+ * function Dog(name) {
+ * this.name = name;
+ * }
+ *
+ * Dog.prototype.bark = function() {
+ * alert('Woof, woof!');
+ * };
+ *
+ * _.forIn(new Dog('Dagny'), function(value, key) {
+ * alert(key);
+ * });
+ * // => alerts 'name' and 'bark' (order is not guaranteed)
+ */
+ var forIn = createIterator(baseIteratorOptions, forEachIteratorOptions, forOwnIteratorOptions, {
+ 'useHas': false
+ });
+
+ /**
+ * Iterates over `object`'s own enumerable properties, executing the `callback`
+ * for each property. The `callback` is bound to `thisArg` and invoked with 3
+ * arguments; (value, key, object).
+ *
+ * @static
+ * @memberOf _
+ * @category Objects
+ * @param {Object} object The object to iterate over.
+ * @param {Function} callback The function called per iteration.
+ * @param {Mixed} [thisArg] The `this` binding for the callback.
+ * @returns {Object} Returns the `object`.
+ * @example
+ *
+ * _.forOwn({ '0': 'zero', '1': 'one', 'length': 2 }, function(num, key) {
+ * alert(key);
+ * });
+ * // => alerts '0', '1', and 'length' (order is not guaranteed)
+ */
+ var forOwn = createIterator(baseIteratorOptions, forEachIteratorOptions, forOwnIteratorOptions);
+
+ /**
+ * Produces a sorted array of the enumerable properties, own and inherited,
+ * of `object` that have function values.
*
* @static
* @memberOf _
@@ -2209,7 +2400,7 @@
var isArguments = function(value) {
return toString.call(value) == '[object Arguments]';
};
- // fallback for browser like IE<9 which detect `arguments` as `[object Object]`
+ // fallback for browser like IE < 9 which detect `arguments` as `[object Object]`
if (!isArguments(arguments)) {
isArguments = function(value) {
return !!(value && hasOwnProperty.call(value, 'callee'));
@@ -2289,7 +2480,7 @@
/**
* Checks if a `value` is empty. Arrays or strings with a length of `0` and
- * objects with no enumerable own properties are considered "empty".
+ * objects with no own enumerable properties are considered "empty".
*
* @static
* @memberOf _
@@ -2536,7 +2727,7 @@
/**
* Checks if a `value` is `NaN`.
- * Note: this is not the same as native `isNaN`, which will return true for
+ * 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
@@ -2653,7 +2844,7 @@
}
/**
- * Produces an array of the `object`'s enumerable own property names.
+ * Produces an array of object`'s own enumerable property names.
*
* @static
* @memberOf _
@@ -2663,14 +2854,14 @@
* @example
*
* _.keys({ 'one': 1, 'two': 2, 'three': 3 });
- * // => ['one', 'two', 'three']
+ * // => ['one', 'two', 'three'] (order is not guaranteed)
*/
- var keys = nativeKeys || createIterator({
- 'args': 'object',
- 'exit': 'if (!objectTypes[typeof object] || object === null) throw TypeError()',
- 'init': '[]',
- 'inLoop': 'result.push(index)'
- });
+ var keys = !nativeKeys ? shimKeys : function(object) {
+ // avoid iterating over the `prototype` property
+ return typeof object == 'function'
+ ? shimKeys(object)
+ : nativeKeys(object);
+ };
/**
* Creates an object composed of the specified properties. Property names may
@@ -2705,9 +2896,8 @@
}
/**
- * Gets the size of a `value` by returning `value.length` if `value` is a
- * string or array, or the number of own enumerable properties if `value` is
- * an object.
+ * Gets the size of `value` by returning `value.length` if `value` is a string
+ * or array, or the number of own enumerable properties if `value` is an object.
*
* @static
* @memberOf _
@@ -2759,11 +2949,30 @@
return value;
}
+ /**
+ * Produces an array of `object`'s own enumerable property values.
+ *
+ * @static
+ * @memberOf _
+ * @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]
+ */
+ var values = createIterator({
+ 'args': 'object',
+ 'init': '[]',
+ 'inLoop': 'result.push(object[index])'
+ });
+
/*--------------------------------------------------------------------------*/
/**
- * Escapes a string for insertion into HTML, replacing `&`, `<`, `"`, `'`,
- * and `/` characters.
+ * Escapes a string for inclusion in HTML, replacing `&`, `<`, `"`, and `'`
+ * characters.
*
* @static
* @memberOf _
@@ -2776,15 +2985,7 @@
* // => "Curly, Larry &amp; Moe"
*/
function escape(string) {
- // the `>` character doesn't require escaping in HTML and has no special
- // meaning unless it's part of a tag or an unquoted attribute value
- // http://mathiasbynens.be/notes/ambiguous-ampersands (semi-related fun fact)
- return (string + '')
- .replace(/&/g, '&amp;')
- .replace(/</g, '&lt;')
- .replace(/"/g, '&quot;')
- .replace(/'/g, '&#x27;')
- .replace(/\//g,'&#x2F;');
+ return (string + '').replace(reUnescapedHtml, escapeHtmlChar);
}
/**
@@ -2837,7 +3038,7 @@
if (arguments.length) {
push.apply(args, arguments);
}
- var result = args.length == 1 ? func.call(lodash, args[0]) : func.apply(lodash, args);
+ var result = func.apply(lodash, args);
if (this._chain) {
result = new LoDash(result);
result._chain = true;
@@ -2865,7 +3066,7 @@
}
/**
- * Resolves the value of `property` on `object`. If the property is a function
+ * Resolves the value of `property` on `object`. If `property` is a function
* it will be invoked and its result returned, else the property value is returned.
*
* @static
@@ -2873,7 +3074,7 @@
* @category Utilities
* @param {Object} object The object to inspect.
* @param {String} property The property to get the result of.
- * @returns {Mixed} Returns the resolved.
+ * @returns {Mixed} Returns the resolved value.
* @example
*
* var object = {
@@ -2898,7 +3099,7 @@
}
/**
- * A JavaScript micro-templating method, similar to John Resig's implementation.
+ * A micro-templating method, similar to John Resig's implementation.
* Lo-Dash templating handles arbitrary delimiters, preserves whitespace, and
* correctly escapes quotes within interpolated code.
*
@@ -2917,13 +3118,13 @@
* compiled({ 'name': 'moe' });
* // => 'hello: moe'
*
- * var list = '% _.forEach(people, function(name) { %> <li><%= name %></li> <% }); %>';
+ * var list = '<% _.forEach(people, function(name) { %> <li><%= name %></li> <% }); %>';
* _.template(list, { 'people': ['moe', 'curly', 'larry'] });
* // => '<li>moe</li><li>curly</li><li>larry</li>'
*
* var template = _.template('<b><%- value %></b>');
* template({ 'value': '<script>' });
- * // => '<b>&lt;script&gt;</b>'
+ * // => '<b>&lt;script></b>'
*
* // using `print`
* var compiled = _.template('<% print("Hello " + epithet); %>');
@@ -2939,7 +3140,6 @@
* template({ 'name': 'Mustache' });
* // => 'Hello Mustache!'
*
- *
* // using the `variable` option
* _.template('<%= data.hasWith %>', { 'hasWith': 'no' }, { 'variable': 'data' });
* // => 'no'
@@ -2983,7 +3183,9 @@
// escape characters that cannot be included in string literals and
// detokenize delimiter code snippets
- text = "__p='" + text.replace(reUnescaped, escapeChar).replace(reToken, detokenize) + "';\n";
+ text = "__p='" + text
+ .replace(reUnescapedString, escapeStringChar)
+ .replace(reToken, detokenize) + "';\n";
// clear stored code snippets
tokenized.length = 0;
@@ -2998,7 +3200,11 @@
'var __p, __t, __j = Array.prototype.join;\n' +
'function print() { __p += __j.call(arguments, \'\') }\n' +
text +
- 'return __p\n}';
+ 'return __p\n}\n' +
+ // add sourceURL for easier debugging
+ // (Narwhal requires a trailing newline to prevent a syntax error)
+ // http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl
+ '//@ sourceURL=/lodash/template/source[' + (templateCounter++) + ']\n';
result = Function('_', 'return ' + text)(lodash);
@@ -3013,8 +3219,8 @@
}
/**
- * Executes the `callback` function `n` times. The `callback` is invoked with
- * 1 argument; (index).
+ * Executes the `callback` function `n` times. The `callback` is bound to
+ * `thisArg` and invoked with 1 argument; (index).
*
* @static
* @memberOf _
@@ -3025,13 +3231,21 @@
* @example
*
* _.times(3, function() { genie.grantWish(); });
+ * // => calls `genie.grantWish()` 3 times
+ *
+ * _.times(3, function() { this.grantWish(); }, genie);
+ * // => also calls `genie.grantWish()` 3 times
*/
function times(n, callback, thisArg) {
+ var index = -1;
if (thisArg) {
- callback = bind(callback, thisArg);
- }
- for (var index = 0; index < n; index++) {
- callback(index);
+ while (++index < n) {
+ callback.call(thisArg, index);
+ }
+ } else {
+ while (++index < n) {
+ callback(index);
+ }
}
}
@@ -3127,7 +3341,7 @@
* @memberOf _
* @type String
*/
- lodash.VERSION = '0.2.0';
+ lodash.VERSION = '0.3.1';
// assign static methods
lodash.after = after;
@@ -3151,6 +3365,8 @@
lodash.first = first;
lodash.flatten = flatten;
lodash.forEach = forEach;
+ lodash.forIn = forIn;
+ lodash.forOwn = forOwn;
lodash.functions = functions;
lodash.groupBy = groupBy;
lodash.has = has;
@@ -3223,15 +3439,15 @@
lodash.head = first;
lodash.include = contains;
lodash.inject = reduce;
- lodash.intersect = intersection;
lodash.methods = functions;
lodash.select = filter;
lodash.tail = rest;
lodash.take = first;
lodash.unique = uniq;
- // add pseudo private template used and removed during the build process
+ // add pseudo private properties used and removed during the build process
lodash._iteratorTemplate = iteratorTemplate;
+ lodash._shimKeys = shimKeys;
/*--------------------------------------------------------------------------*/
@@ -3252,14 +3468,11 @@
LoDash.prototype[methodName] = function() {
var value = this._wrapped;
- if (arguments.length) {
- func.apply(value, arguments);
- } else {
- func.call(value);
- }
+ func.apply(value, arguments);
+
// IE compatibility mode and IE < 9 have buggy Array `shift()` and `splice()`
// functions that fail to remove the last element, `value[0]`, of
- // array-like-objects even though the `length` property is set to `0`.
+ // 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.
if (value.length === 0) {
@@ -3279,7 +3492,7 @@
LoDash.prototype[methodName] = function() {
var value = this._wrapped,
- result = arguments.length ? func.apply(value, arguments) : func.call(value);
+ result = func.apply(value, arguments);
if (this._chain) {
result = new LoDash(result);
999 lib/underscore.js
View
@@ -1,999 +0,0 @@
-// Underscore.js 1.3.1
-// (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.1';
-
- // 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)) 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)) 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) {
- if (index == 0) {
- shuffled[0] = value;
- } else {
- 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, iterator, context) {
- 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;
- 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(iterable) {
- if (!iterable) return [];
- if (iterable.toArray) return iterable.toArray();
- if (_.isArray(iterable)) return slice.call(iterable);
- if (_.isArguments(iterable)) return slice.call(iterable);
- return _.values(iterable);
- };
-
- // Return the number of elements in an object.
- _.size = function(obj) {
- return _.toArray(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`. The **guard** check allows it to work
- // with `_.map`.
- _.first = _.head = 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 result = [];
- _.reduce(initial, function(memo, el, i) {
- if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) {
- memo[memo.length] = el;
- result[result.length] = array[i];
- }
- return memo;
- }, []);
- return result;
- };
-
- // 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));
- 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(func, 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