/*! * Lo-Dash 1.0.0-rc.3 (Custom Build) * Build: `lodash underscore -d -o ./lodash.underscore.js` * (c) 2012 John-David Dalton * Based on Underscore.js 1.4.3 * (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc. * Available under MIT license */ ;(function(window, undefined) { /** Detect free variable `exports` */ var freeExports = typeof exports == 'object' && exports; /** Detect free variable `global` and use it as `window` */ var freeGlobal = typeof global == 'object' && global; if (freeGlobal.global === freeGlobal) { window = freeGlobal; } /** Used for array and object method references */ var arrayRef = [], // avoid a Closure Compiler bug by creatively creating an object objectRef = new function(){}; /** Used to generate unique IDs */ var idCounter = 0; /** Used internally to indicate various things */ var indicatorObject = objectRef; /** Used to restore the original `_` reference in `noConflict` */ var oldDash = window._; /** Used to detect template delimiter values that require a with-statement */ var reComplexDelimiter = /[-?+=!~*%&^<>|{(\/]|\[\D|\b(?:delete|in|instanceof|new|typeof|void)\b/; /** Used to match HTML entities */ var reEscapedHtml = /&(?:amp|lt|gt|quot|#x27);/g; /** Used to match empty string literals in compiled template source */ var reEmptyStringLeading = /\b__p \+= '';/g, reEmptyStringMiddle = /\b(__p \+=) '' \+/g, reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g; /** Used to match regexp flags from their coerced string values */ var reFlags = /\w*$/; /** Used to insert the data object variable into compiled template source */ var reInsertVariable = /(?:__e|__t = )\(\s*(?![\d\s"']|this\.)/g; /** Used to detect if a method is native */ var reNative = RegExp('^' + (objectRef.valueOf + '') .replace(/[.*+?^=!:${}()|[\]\/\\]/g, '\\$&') .replace(/valueOf|for [^\]]+/g, '.+?') + '$' ); /** * Used to match ES6 template delimiters * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-7.8.6 */ var reEsTemplate = /\$\{((?:(?=\\?)\\?[\s\S])*?)}/g; /** Used to match "interpolate" template delimiters */ var reInterpolate = /<%=([\s\S]+?)%>/g; /** Used to ensure capturing order of template delimiters */ var reNoMatch = /($^)/; /** Used to match HTML characters */ 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 = [ 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf' ]; /** Used to make template sourceURLs easier to identify */ var templateCounter = 0; /** Native method shortcuts */ var ceil = Math.ceil, concat = arrayRef.concat, floor = Math.floor, getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf, hasOwnProperty = objectRef.hasOwnProperty, push = arrayRef.push, propertyIsEnumerable = objectRef.propertyIsEnumerable, toString = objectRef.toString; /* Native method shortcuts for methods with the same name as other `lodash` methods */ var nativeBind = reNative.test(nativeBind = slice.bind) && nativeBind, nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray, nativeIsFinite = window.isFinite, nativeIsNaN = window.isNaN, nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys, nativeMax = Math.max, nativeMin = Math.min, nativeRandom = Math.random; /** `Object#toString` result shortcuts */ var argsClass = '[object Arguments]', arrayClass = '[object Array]', boolClass = '[object Boolean]', dateClass = '[object Date]', funcClass = '[object Function]', numberClass = '[object Number]', objectClass = '[object Object]', regexpClass = '[object RegExp]', stringClass = '[object String]'; /** Detect various environments */ var isIeOpera = !!window.attachEvent, isV8 = nativeBind && !/\n|true/.test(nativeBind + isIeOpera); /* Detect if `Function#bind` exists and is inferred to be fast (all but V8) */ var isBindFast = nativeBind && !isV8; /** * Detect if `Array#shift` and `Array#splice` augment array-like objects * incorrectly: * * Firefox < 10, 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`. * 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 hasObjectSpliceBug = (hasObjectSpliceBug = { '0': 1, 'length': 1 }, arrayRef.splice.call(hasObjectSpliceBug, 0, 1), hasObjectSpliceBug[0]); /** Detect if `arguments` objects are `Object` objects (all but Opera < 10.5) */ var argsAreObjects = arguments.constructor == Object; /** * Detect lack of support for accessing string characters by index: * * IE < 8 can't access characters by index and IE 8 can only access * characters by index on string literals. */ var noCharByIndex = ('x'[0] + Object('x')[0]) != 'xx'; /** * Detect if sourceURL syntax is usable without erroring: * * The JS engine embedded in Adobe products will throw a syntax error when * it encounters a single line comment beginning with the `@` symbol. * * The JS engine in Narwhal will generate the function `function anonymous(){//}` * and throw a syntax error. * * Avoid comments beginning `@` symbols in IE because they are part of its * non-standard conditional compilation support. * http://msdn.microsoft.com/en-us/library/121hztk3(v=vs.94).aspx */ try { var useSourceURL = (Function('//@')(), !isIeOpera); } catch(e) { } /** 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' }; /*--------------------------------------------------------------------------*/ /** * Creates a `lodash` object, that wraps the given `value`, to enable * method chaining. * * The chainable wrapper functions are: * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`, `compose`, * `concat`, `countBy`, `debounce`, `defaults`, `defer`, `delay`, `difference`, * `filter`, `flatten`, `forEach`, `forIn`, `forOwn`, `functions`, `groupBy`, * `initial`, `intersection`, `invert`, `invoke`, `keys`, `map`, `max`, `memoize`, * `merge`, `min`, `object`, `omit`, `once`, `pairs`, `partial`, `pick`, `pluck`, * `push`, `range`, `reject`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, * `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `union`, `uniq`, * `unshift`, `values`, `where`, `without`, `wrap`, and `zip` * * The non-chainable wrapper functions are: * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `has`, `identity`, * `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`, `isElement`, `isEmpty`, * `isEqual`, `isFinite`, `isFunction`, `isNaN`, `isNull`, `isNumber`, `isObject`, * `isPlainObject`, `isRegExp`, `isString`, `isUndefined`, `join`, `lastIndexOf`, * `mixin`, `noConflict`, `pop`, `random`, `reduce`, `reduceRight`, `result`, * `shift`, `size`, `some`, `sortedIndex`, `template`, `unescape`, and `uniqueId` * * The wrapper functions `first` and `last` return wrapped values when `n` is * passed, otherwise they return unwrapped values. * * @name _ * @constructor * @category Chaining * @param {Mixed} value The value to wrap in a `lodash` instance. * @returns {Object} Returns a `lodash` instance. */ function lodash(value) { // exit early if already wrapped, even if wrapped by a different `lodash` constructor if (value && typeof value == 'object' && value.__wrapped__) { return value; } // allow invoking `lodash` without the `new` operator if (!(this instanceof lodash)) { return new lodash(value); } this.__wrapped__ = value; } /** * By default, the template delimiters used by Lo-Dash are similar to those in * embedded Ruby (ERB). Change the following template settings to use alternative * delimiters. * * @static * @memberOf _ * @type Object */ lodash.templateSettings = { /** * Used to detect `data` property values to be HTML-escaped. * * @static * @memberOf _.templateSettings * @type RegExp */ 'escape': /<%-([\s\S]+?)%>/g, /** * Used to detect code to be evaluated. * * @static * @memberOf _.templateSettings * @type RegExp */ 'evaluate': /<%([\s\S]+?)%>/g, /** * Used to detect `data` property values to inject. * * @static * @memberOf _.templateSettings * @type RegExp */ 'interpolate': reInterpolate, /** * Used to reference the data object in the template text. * * @static * @memberOf _.templateSettings * @type String */ 'variable': '' }; /*--------------------------------------------------------------------------*/ /** Reusable iterator options for `assign` and `defaults` */ var assignIteratorOptions = { 'args': 'object, source, guard', 'top': "for (var argsIndex = 1, argsLength = typeof guard == 'number' ? 2 : arguments.length; argsIndex < argsLength; argsIndex++) {\n" + ' if ((iteratee = arguments[argsIndex])) {', 'objectLoop': 'result[index] = iteratee[index]', 'bottom': ' }\n}' }; /** * Reusable iterator options shared by `each`, `forIn`, and `forOwn`. */ var eachIteratorOptions = { 'args': 'collection, callback, thisArg', 'top': "callback = callback && typeof thisArg == 'undefined' ? callback : createCallback(callback, thisArg)", 'arrayLoop': 'if (callback(iteratee[index], index, collection) === false) return result', 'objectLoop': 'if (callback(iteratee[index], index, collection) === false) return result' }; /** Reusable iterator options for `forIn` and `forOwn` */ var forOwnIteratorOptions = { 'arrayLoop': null }; /*--------------------------------------------------------------------------*/ /** * Used by `_.max` and `_.min` as the default `callback` when a given * `collection` is a string value. * * @private * @param {String} value The character to inspect. * @returns {Number} Returns the code unit of given character. */ function charAtCallback(value) { return value.charCodeAt(0); } /** * Used by `sortBy` to compare transformed `collection` values, stable sorting * them in ascending order. * * @private * @param {Object} a The object to compare to `b`. * @param {Object} b The object to compare to `a`. * @returns {Number} Returns the sort order indicator of `1` or `-1`. */ function compareAscending(a, b) { var ai = a.index, bi = b.index; a = a.criteria; b = b.criteria; // ensure a stable sort in V8 and other engines // http://code.google.com/p/v8/issues/detail?id=90 if (a !== b) { if (a > b || typeof a == 'undefined') { return 1; } if (a < b || typeof b == 'undefined') { return -1; } } return ai < bi ? -1 : 1; } /** * Creates a function that, when called, invokes `func` with the `this` * binding of `thisArg` and prepends any `partailArgs` to the arguments passed * to the bound function. * * @private * @param {Function|String} func The function to bind or the method name. * @param {Mixed} [thisArg] The `this` binding of `func`. * @param {Array} partialArgs An array of arguments to be partially applied. * @returns {Function} Returns the new bound function. */ function createBound(func, thisArg, partialArgs) { function bound() { // `Function#bind` spec // http://es5.github.com/#x15.3.4.5 var args = arguments, thisBinding = thisArg; if (partialArgs.length) { args = args.length ? partialArgs.concat(slice(args)) : partialArgs; } if (this instanceof bound) { // ensure `new bound` is an instance of `bound` and `func` noop.prototype = func.prototype; thisBinding = new noop; noop.prototype = null; // mimic the constructor's `return` behavior // http://es5.github.com/#x13.2.2 var result = func.apply(thisBinding, args); return isObject(result) ? result : thisBinding; } return func.apply(thisBinding, args); } return bound; } /** * Produces an iteration callback bound to an optional `thisArg`. If `func` is * a property name, the callback will return the property value for a given element. * * @private * @param {Function|String} [func=identity|property] The function called per * iteration or property name to query. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @param {Object} [accumulating] Used to indicate that the callback should * accept an `accumulator` argument. * @returns {Function} Returns a callback function. */ function createCallback(func, thisArg, accumulating) { if (!func) { return identity; } if (typeof func != 'function') { return function(object) { return object[func]; }; } if (typeof thisArg != 'undefined') { if (accumulating) { return function(accumulator, value, index, object) { return func.call(thisArg, accumulator, value, index, object); }; } return function(value, index, object) { return func.call(thisArg, value, index, object); }; } return func; } /** * Creates compiled iteration functions. * * @private * @param {Object} [options1, options2, ...] The compile options object(s). * useHas - A boolean to specify using `hasOwnProperty` checks in the object loop. * args - A string of comma separated arguments the iteration function will accept. * top - A string of code to execute before the iteration branches. * arrayLoop - A string of code to execute in the array loop. * objectLoop - A string of code to execute in the object loop. * bottom - A string of code to execute after the iteration branches. * * @returns {Function} Returns the compiled function. */ function createIterator() { var data = { 'arrayLoop': '', 'bottom': '', 'hasDontEnumBug': hasDontEnumBug, 'objectLoop': '', 'nonEnumArgs': nonEnumArgs, 'noCharByIndex': noCharByIndex, 'shadowed': shadowed, 'top': '', 'useHas': true }; // merge options into a template data object for (var object, index = 0; object = arguments[index]; index++) { for (var key in object) { data[key] = object[key]; } } var args = data.args; data.firstArg = /^[^,]+/.exec(args)[0]; // create the function factory var factory = Function( 'createCallback, hasOwnProperty, isString, objectTypes, ' + 'nativeKeys, propertyIsEnumerable', 'return function(' + args + ') {\n' + (data) + '\n}' ); // return the compiled function return factory( createCallback, hasOwnProperty, isString, objectTypes, nativeKeys, propertyIsEnumerable ); } /** * A function compiled to iterate `arguments` objects, arrays, objects, and * strings consistenly across environments, executing the `callback` for each * element in the `collection`. The `callback` is bound to `thisArg` and invoked * with three arguments; (value, index|key, collection). Callbacks may exit * iteration early by explicitly returning `false`. * * @private * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array|Object|String} Returns `collection`. */ var each = function (collection, callback, thisArg) { var index, iteratee = collection, result = collection; if (!collection) return result; callback = callback && typeof thisArg == 'undefined' ? callback : createCallback(callback, thisArg); var length = iteratee.length; index = -1; if (typeof length == 'number') { while (++index < length) { if (callback(iteratee[index], index, collection) === indicatorObject) return result } } else { for (index in iteratee) { if (hasOwnProperty.call(iteratee, index)) { if (callback(iteratee[index], index, collection) === indicatorObject) return result; } } } }; /** * Used by `template` to escape characters for inclusion in compiled * string literals. * * @private * @param {String} match The matched character to escape. * @returns {String} Returns the escaped character. */ function escapeStringChar(match) { return '\\' + stringEscapes[match]; } /** * Used by `escape` to convert characters to HTML entities. * * @private * @param {String} match The matched character to escape. * @returns {String} Returns the escaped character. */ function escapeHtmlChar(match) { return htmlEscapes[match]; } /** * Checks if `value` is a DOM node in IE < 9. * * @private * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is a DOM node, else `false`. */ function isNode(value) { // IE < 9 presents DOM nodes as `Object` objects except they have `toString` // methods that are `typeof` "string" and still can coerce nodes to strings return typeof value.toString != 'function' && typeof (value + '') == 'string'; } /** * A no-operation function. * * @private */ function noop() { // no operation performed } /** * Slices the `collection` from the `start` index up to, but not including, * the `end` index. * * Note: This function is used, instead of `Array#slice`, to support node lists * in IE < 9 and to ensure dense arrays are returned. * * @private * @param {Array|Object|String} collection The collection to slice. * @param {Number} start The start index. * @param {Number} end The end index. * @returns {Array} Returns the new array. */ function slice(array, start, end) { start || (start = 0); if (typeof end == 'undefined') { end = array ? array.length : 0; } var index = -1, length = end - start || 0, result = Array(length < 0 ? 0 : length); while (++index < length) { result[index] = array[start + index]; } return result; } /** * Used by `unescape` to convert HTML entities to characters. * * @private * @param {String} match The matched character to unescape. * @returns {String} Returns the unescaped character. */ function unescapeHtmlChar(match) { return htmlUnescapes[match]; } /*--------------------------------------------------------------------------*/ /** * Assigns own enumerable properties of source object(s) to the `destination` * object. Subsequent sources will overwrite propery assignments of previous * sources. * * @static * @memberOf _ * @alias extend * @category Objects * @param {Object} object The destination object. * @param {Object} [source1, source2, ...] The source objects. * @returns {Object} Returns the destination object. * @example * * _.assign({ 'name': 'moe' }, { 'age': 40 }); * // => { 'name': 'moe', 'age': 40 } */ function assign(object) { if (!object) { return object; } for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { var iteratee = arguments[argsIndex]; if (iteratee) { for (var key in iteratee) { object[key] = iteratee[key]; } } } return object; } /** * Checks if `value` is an `arguments` object. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is an `arguments` object, else `false`. * @example * * (function() { return _.isArguments(arguments); })(1, 2, 3); * // => true * * _.isArguments([1, 2, 3]); * // => false */ lodash.isArguments = function(value) { return toString.call(value) == argsClass; } // fallback for browsers that can't detect `arguments` objects by [[Class]] if (!lodash.isArguments(arguments)) { lodash.isArguments = function(value) { return value ? hasOwnProperty.call(value, 'callee') : false; }; } /** * Iterates over `object`'s own and inherited enumerable properties, executing * the `callback` for each property. The `callback` is bound to `thisArg` and * invoked with three arguments; (value, key, object). Callbacks may exit iteration * early by explicitly returning `false`. * * @static * @memberOf _ * @category Objects * @param {Object} object The object to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Object} Returns `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 = function (collection, callback) { var index, iteratee = collection, result = collection; if (!collection) return result; callback || (callback = identity); for (index in iteratee) { if (callback(iteratee[index], index, collection) === indicatorObject) return result; } return result }; /** * Iterates over an object's own enumerable properties, executing the `callback` * for each property. The `callback` is bound to `thisArg` and invoked with three * arguments; (value, key, object). Callbacks may exit iteration early by explicitly * returning `false`. * * @static * @memberOf _ * @category Objects * @param {Object} object The object to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Object} Returns `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 = function (collection, callback) { var index, iteratee = collection, result = collection; if (!collection) return result; callback || (callback = identity); for (index in iteratee) { if (hasOwnProperty.call(iteratee, index)) { if (callback(iteratee[index], index, collection) === indicatorObject) return result; } } return result }; /** * A fallback implementation of `isPlainObject` that checks if a given `value` * is an object created by the `Object` constructor, assuming objects created * by the `Object` constructor have no inherited enumerable properties and that * there are no `Object.prototype` extensions. * * @private * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if `value` is a plain object, else `false`. */ function shimIsPlainObject(value) { // avoid non-objects and false positives for `arguments` objects var result = false; if (!(value && typeof value == 'object') || isArguments(value)) { return result; } // check that the constructor is `Object` (i.e. `Object instanceof Object`) var ctor = value.constructor; if ((!isFunction(ctor)) || ctor instanceof ctor) { // In most environments an object's own properties are iterated before // its inherited properties. If the last iterated property is an object's // own property then there are no inherited enumerable properties. forIn(value, function(value, key) { result = key; }); return result === false || hasOwnProperty.call(value, result); } return result; } /** * A fallback 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. */ function shimKeys(object) { var result = []; forOwn(object, function(value, key) { result.push(key); }); return result; } /** * Used to convert characters to HTML entities: * * Though the `>` character is escaped for symmetry, characters like `>` and `/` * 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 (under "semi-related fun fact") */ var htmlEscapes = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; /** Used to convert HTML entities to characters */ var htmlUnescapes = invert(htmlEscapes); /*--------------------------------------------------------------------------*/ /** * Creates a clone of `value`. If `deep` is `true`, nested objects will also * be cloned, otherwise they will be assigned by reference. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to clone. * @param {Boolean} deep A flag to indicate a deep clone. * @param- {Object} [guard] Internally used to allow this method to work with * others like `_.map` without using their callback `index` argument for `deep`. * @param- {Array} [stackA=[]] Internally used to track traversed source objects. * @param- {Array} [stackB=[]] Internally used to associate clones with their * source counterparts. * @returns {Mixed} Returns the cloned `value`. * @example * * var stooges = [ * { 'name': 'moe', 'age': 40 }, * { 'name': 'larry', 'age': 50 }, * { 'name': 'curly', 'age': 60 } * ]; * * var shallow = _.clone(stooges); * shallow[0] === stooges[0]; * // => true * * var deep = _.clone(stooges, true); * deep[0] === stooges[0]; * // => false */ function clone(value) { return value && objectTypes[typeof value] ? (isArray(value) ? slice(value) : assign({}, value)) : value } /** * Assigns own enumerable properties of source object(s) to the `destination` * object for all `destination` properties that resolve to `null`/`undefined`. * Once a property is set, additional defaults of the same property will be * ignored. * * @static * @memberOf _ * @category Objects * @param {Object} object The destination object. * @param {Object} [default1, default2, ...] The default objects. * @returns {Object} Returns the destination object. * @example * * var iceCream = { 'flavor': 'chocolate' }; * _.defaults(iceCream, { 'flavor': 'vanilla', 'sprinkles': 'rainbow' }); * // => { 'flavor': 'chocolate', 'sprinkles': 'rainbow' } */ function defaults(object) { if (!object) { return object; } for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) { var iteratee = arguments[argsIndex]; if (iteratee) { for (var key in iteratee) { if (object[key] == null) { object[key] = iteratee[key]; } } } } return object; } /** * Creates a sorted array of all enumerable properties, own and inherited, * of `object` that have function values. * * @static * @memberOf _ * @alias methods * @category Objects * @param {Object} object The object to inspect. * @returns {Array} Returns a new array of property names that have function values. * @example * * _.functions(_); * // => ['all', 'any', 'bind', 'bindAll', 'clone', 'compact', 'compose', ...] */ function functions(object) { var result = []; forIn(object, function(value, key) { if (isFunction(value)) { result.push(key); } }); return result.sort(); } /** * Checks if the specified object `property` exists and is a direct property, * instead of an inherited property. * * @static * @memberOf _ * @category Objects * @param {Object} object The object to check. * @param {String} property The property to check for. * @returns {Boolean} Returns `true` if key is a direct property, else `false`. * @example * * _.has({ 'a': 1, 'b': 2, 'c': 3 }, 'b'); * // => true */ function has(object, property) { return object ? hasOwnProperty.call(object, property) : false; } /** * Creates an object composed of the inverted keys and values of the given `object`. * * @static * @memberOf _ * @category Objects * @param {Object} object The object to invert. * @returns {Object} Returns the created inverted object. * @example * * _.invert({ 'first': 'Moe', 'second': 'Larry', 'third': 'Curly' }); * // => { 'Moe': 'first', 'Larry': 'second', 'Curly': 'third' } (order is not guaranteed) */ function invert(object) { var result = {}; forOwn(object, function(value, key) { result[value] = key; }); return result; } /** * Checks if `value` is an array. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is an array, else `false`. * @example * * (function() { return _.isArray(arguments); })(); * // => false * * _.isArray([1, 2, 3]); * // => true */ var isArray = nativeIsArray || function(value) { // `instanceof` may cause a memory leak in IE 7 if `value` is a host object // http://ajaxian.com/archives/working-aroung-the-instanceof-memory-leak return (argsAreObjects && value instanceof Array) || toString.call(value) == arrayClass; }; /** * Checks if `value` is a boolean (`true` or `false`) value. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is a boolean value, else `false`. * @example * * _.isBoolean(null); * // => false */ function isBoolean(value) { return value === true || value === false || toString.call(value) == boolClass; } /** * Checks if `value` is a date. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is a date, else `false`. * @example * * _.isDate(new Date); * // => true */ function isDate(value) { return value instanceof Date || toString.call(value) == dateClass; } /** * Checks if `value` is a DOM element. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is a DOM element, else `false`. * @example * * _.isElement(document.body); * // => true */ function isElement(value) { return value ? value.nodeType === 1 : false; } /** * Checks if `value` is empty. Arrays, strings, or `arguments` objects with a * length of `0` and objects with no own enumerable properties are considered * "empty". * * @static * @memberOf _ * @category Objects * @param {Array|Object|String} value The value to inspect. * @returns {Boolean} Returns `true` if the `value` is empty, else `false`. * @example * * _.isEmpty([1, 2, 3]); * // => false * * _.isEmpty({}); * // => true * * _.isEmpty(''); * // => true */ function isEmpty(value) { if (!value) { return true; } if (isArray(value) || isString(value)) { return !value.length; } for (var key in value) { if (hasOwnProperty.call(value, key)) { return false; } } return true; } /** * Performs a deep comparison between two values to determine if they are * equivalent to each other. * * @static * @memberOf _ * @category Objects * @param {Mixed} a The value to compare. * @param {Mixed} b The other value to compare. * @param- {Object} [stackA=[]] Internally used track traversed `a` objects. * @param- {Object} [stackB=[]] Internally used track traversed `b` objects. * @returns {Boolean} Returns `true` if the values are equvalent, else `false`. * @example * * var moe = { 'name': 'moe', 'luckyNumbers': [13, 27, 34] }; * var clone = { 'name': 'moe', 'luckyNumbers': [13, 27, 34] }; * * moe == clone; * // => false * * _.isEqual(moe, clone); * // => true */ function isEqual(a, b, stackA, stackB) { // 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; } // compare [[Class]] names var className = toString.call(a), otherName = toString.call(b); if (className != otherName) { return false; } switch (className) { case boolClass: case dateClass: // coerce dates and booleans to numbers, dates to milliseconds and booleans // to `1` or `0`, treating invalid dates coerced to `NaN` as not equal return +a == +b; case numberClass: // 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 regexpClass: case stringClass: // coerce regexes to strings (http://es5.github.com/#x15.10.6.4) // treat string primitives and their corresponding object instances as equal return a == b + ''; } var isArr = className == arrayClass; if (!isArr) { // unwrap any `lodash` wrapped values if (a.__wrapped__ || b.__wrapped__) { return isEqual(a.__wrapped__ || a, b.__wrapped__ || b); } // exit for functions and DOM nodes if (className != objectClass) { return false; } // in older versions of Opera, `arguments` objects have `Array` constructors var ctorA = a.constructor, ctorB = b.constructor; // non `Object` object instances with different constructors are not equal if (ctorA != ctorB && !( isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB )) { return false; } } // assume cyclic structures are equal // the algorithm for detecting cyclic structures is adapted from ES 5.1 // section 15.12.3, abstract operation `JO` (http://es5.github.com/#x15.12.3) stackA || (stackA = []); stackB || (stackB = []); var length = stackA.length; while (length--) { if (stackA[length] == a) { return stackB[length] == b; } } var index = -1, result = true, size = 0; // add `a` and `b` to the stack of traversed objects stackA.push(a); stackB.push(b); // recursively compare objects and arrays (susceptible to call stack limits) if (isArr) { // compare 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--) { if (!(result = isEqual(a[size], b[size], stackA, stackB))) { break; } } } return result; } // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys` // which, in this case, is more costly forIn(a, function(value, key, a) { if (hasOwnProperty.call(a, key)) { // count the number of properties. size++; // deep compare each property value. return !(result = hasOwnProperty.call(b, key) && isEqual(value, b[key], stackA, stackB)) && indicatorObject; } }); if (result) { // ensure both objects have the same number of properties forIn(b, function(value, key, b) { if (hasOwnProperty.call(b, key)) { // `size` will be `-1` if `b` has more properties than `a` return !(result = --size > -1) && indicatorObject; } }); } return result; } /** * Checks if `value` is, or can be coerced to, a finite number. * * Note: This is not the same as native `isFinite`, which will return true for * booleans and empty strings. See http://es5.github.com/#x15.1.2.5. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is a finite number, else `false`. * @example * * _.isFinite(-101); * // => true * * _.isFinite('10'); * // => true * * _.isFinite(true); * // => false * * _.isFinite(''); * // => false * * _.isFinite(Infinity); * // => false */ function isFinite(value) { return nativeIsFinite(value) && !nativeIsNaN(parseFloat(value)); } /** * Checks if `value` is a function. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is a function, else `false`. * @example * * _.isFunction(_); * // => true */ function isFunction(value) { return typeof value == 'function'; } // fallback for older versions of Chrome and Safari if (isFunction(/x/)) { isFunction = function(value) { return value instanceof Function || toString.call(value) == funcClass; }; } /** * Checks if `value` is the language type of Object. * (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is an object, else `false`. * @example * * _.isObject({}); * // => true * * _.isObject([1, 2, 3]); * // => true * * _.isObject(1); * // => false */ function isObject(value) { // check if the value is the ECMAScript language type of Object // http://es5.github.com/#x8 // and avoid a V8 bug // http://code.google.com/p/v8/issues/detail?id=2291 return value ? objectTypes[typeof value] : false; } /** * Checks if `value` is `NaN`. * * Note: This is not the same as native `isNaN`, which will return `true` for * `undefined` and other values. See http://es5.github.com/#x15.1.2.4. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is `NaN`, else `false`. * @example * * _.isNaN(NaN); * // => true * * _.isNaN(new Number(NaN)); * // => true * * isNaN(undefined); * // => true * * _.isNaN(undefined); * // => false */ function isNaN(value) { // `NaN` as a primitive is the only value that is not equal to itself // (perform the [[Class]] check first to avoid errors with some host objects in IE) return isNumber(value) && value != +value } /** * Checks if `value` is `null`. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is `null`, else `false`. * @example * * _.isNull(null); * // => true * * _.isNull(undefined); * // => false */ function isNull(value) { return value === null; } /** * Checks if `value` is a number. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is a number, else `false`. * @example * * _.isNumber(8.4 * 5); * // => true */ function isNumber(value) { return typeof value == 'number' || toString.call(value) == numberClass; } /** * Checks if `value` is a regular expression. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is a regular expression, else `false`. * @example * * _.isRegExp(/moe/); * // => true */ function isRegExp(value) { return value instanceof RegExp || toString.call(value) == regexpClass; } /** * Checks if `value` is a string. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is a string, else `false`. * @example * * _.isString('moe'); * // => true */ function isString(value) { return typeof value == 'string' || toString.call(value) == stringClass; } /** * Checks if `value` is `undefined`. * * @static * @memberOf _ * @category Objects * @param {Mixed} value The value to check. * @returns {Boolean} Returns `true` if the `value` is `undefined`, else `false`. * @example * * _.isUndefined(void 0); * // => true */ function isUndefined(value) { return typeof value == 'undefined'; } /** * Creates an array composed of the own enumerable property names of `object`. * * @static * @memberOf _ * @category Objects * @param {Object} object The object to inspect. * @returns {Array} Returns a new array of property names. * @example * * _.keys({ 'one': 1, 'two': 2, 'three': 3 }); * // => ['one', 'two', 'three'] (order is not guaranteed) */ var keys = !nativeKeys ? shimKeys : function(object) { return (isObject(object) ? nativeKeys(object) : []); }; /** * Creates a shallow clone of `object` excluding the specified properties. * Property names may be specified as individual arguments or as arrays of * property names. If `callback` is passed, it will be executed for each property * in the `object`, omitting the properties `callback` returns truthy for. The * `callback` is bound to `thisArg` and invoked with three arguments; (value, key, object). * * @static * @memberOf _ * @category Objects * @param {Object} object The source object. * @param {Function|String} callback|[prop1, prop2, ...] The properties to omit * or the function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Object} Returns an object without the omitted properties. * @example * * _.omit({ 'name': 'moe', 'age': 40, 'userid': 'moe1' }, 'userid'); * // => { 'name': 'moe', 'age': 40 } * * _.omit({ 'name': 'moe', '_hint': 'knucklehead', '_seed': '96c4eb' }, function(value, key) { * return key.charAt(0) == '_'; * }); * // => { 'name': 'moe' } */ function omit(object) { var props = concat.apply(arrayRef, arguments), result = {}; forIn(object, function(value, key) { if (indexOf(props, key, 1) < 0) { result[key] = value; } }); return result; } /** * Creates a two dimensional array of the given object's key-value pairs, * i.e. `[[key1, value1], [key2, value2]]`. * * @static * @memberOf _ * @category Objects * @param {Object} object The object to inspect. * @returns {Array} Returns new array of key-value pairs. * @example * * _.pairs({ 'moe': 30, 'larry': 40, 'curly': 50 }); * // => [['moe', 30], ['larry', 40], ['curly', 50]] (order is not guaranteed) */ function pairs(object) { var result = []; forOwn(object, function(value, key) { result.push([key, value]); }); return result; } /** * Creates a shallow clone of `object` composed of the specified properties. * Property names may be specified as individual arguments or as arrays of * property names. If `callback` is passed, it will be executed for each property * in the `object`, picking the properties `callback` returns truthy for. The * `callback` is bound to `thisArg` and invoked with three arguments; (value, key, object). * * @static * @memberOf _ * @category Objects * @param {Object} object The source object. * @param {Function|String} callback|[prop1, prop2, ...] The properties to pick * or the function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Object} Returns an object composed of the picked properties. * @example * * _.pick({ 'name': 'moe', 'age': 40, 'userid': 'moe1' }, 'name', 'age'); * // => { 'name': 'moe', 'age': 40 } * * _.pick({ 'name': 'moe', '_hint': 'knucklehead', '_seed': '96c4eb' }, function(value, key) { * return key.charAt(0) != '_'; * }); * // => { 'name': 'moe' } */ function pick(object) { var index = 0, props = concat.apply(arrayRef, arguments), length = props.length, result = {}; while (++index < length) { var prop = props[index]; if (prop in object) { result[prop] = object[prop]; } } return result; } /** * Creates an array composed of the own enumerable property values of `object`. * * @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] */ function values(object) { var result = []; forOwn(object, function(value) { result.push(value); }); return result; } /*--------------------------------------------------------------------------*/ /** * Checks if a given `target` element is present in a `collection` using strict * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used * as the offset from the end of the collection. * * @static * @memberOf _ * @alias include * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Mixed} target The value to check for. * @param {Number} [fromIndex=0] The index to search from. * @returns {Boolean} Returns `true` if the `target` element is found, else `false`. * @example * * _.contains([1, 2, 3], 1); * // => true * * _.contains([1, 2, 3], 1, 2); * // => false * * _.contains({ 'name': 'moe', 'age': 40 }, 'moe'); * // => true * * _.contains('curly', 'ur'); * // => true */ function contains(collection, target) { var length = collection ? collection.length : 0, result = false; if (typeof length == 'number') { result = indexOf(collection, target) > -1; } else { each(collection, function(value) { return (result = value === target) && indicatorObject; }); } return result; } /** * Creates an object composed of keys returned from running each element of * `collection` through a `callback`. The corresponding value of each key is * the number of times the key was returned by `callback`. The `callback` is * bound to `thisArg` and invoked with three arguments; (value, index|key, collection). * The `callback` argument may also be the name of a property to count by (e.g. 'length'). * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|String} callback|property The function called per iteration * or property name to count by. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Object} Returns the composed aggregate object. * @example * * _.countBy([4.3, 6.1, 6.4], function(num) { return Math.floor(num); }); * // => { '4': 1, '6': 2 } * * _.countBy([4.3, 6.1, 6.4], function(num) { return this.floor(num); }, Math); * // => { '4': 1, '6': 2 } * * _.countBy(['one', 'two', 'three'], 'length'); * // => { '3': 2, '5': 1 } */ function countBy(collection, callback, thisArg) { var result = {}; callback = createCallback(callback, thisArg); forEach(collection, function(value, key, collection) { key = callback(value, key, collection); (hasOwnProperty.call(result, key) ? result[key]++ : result[key] = 1); }); return result; } /** * Checks if the `callback` returns a truthy value for **all** elements of a * `collection`. The `callback` is bound to `thisArg` and invoked with three * arguments; (value, index|key, collection). * * @static * @memberOf _ * @alias all * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Boolean} Returns `true` if all elements pass the callback check, * else `false`. * @example * * _.every([true, 1, null, 'yes'], Boolean); * // => false */ function every(collection, callback, thisArg) { var result = true; callback = createCallback(callback, thisArg); if (isArray(collection)) { var index = -1, length = collection.length; while (++index < length) { if (!(result = !!callback(collection[index], index, collection))) { break; } } } else { each(collection, function(value, index, collection) { return !(result = !!callback(value, index, collection)) && indicatorObject; }); } return result; } /** * Examines each element in a `collection`, returning an array of all elements * the `callback` returns truthy for. The `callback` is bound to `thisArg` and * invoked with three arguments; (value, index|key, collection). * * @static * @memberOf _ * @alias select * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array} Returns a new array of elements that passed the callback check. * @example * * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); * // => [2, 4, 6] */ function filter(collection, callback, thisArg) { var result = []; callback = createCallback(callback, thisArg); if (isArray(collection)) { var index = -1, length = collection.length; while (++index < length) { var value = collection[index]; if (callback(value, index, collection)) { result.push(value); } } } else { each(collection, function(value, index, collection) { if (callback(value, index, collection)) { result.push(value); } }); } return result; } /** * Examines each element in a `collection`, returning the first one the `callback` * returns truthy for. The function returns as soon as it finds an acceptable * element, and does not iterate over the entire `collection`. The `callback` is * bound to `thisArg` and invoked with three arguments; (value, index|key, collection). * * @static * @memberOf _ * @alias detect * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Mixed} Returns the element that passed the callback check, * else `undefined`. * @example * * var even = _.find([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); * // => 2 */ function find(collection, callback, thisArg) { var result; callback = createCallback(callback, thisArg); forEach(collection, function(value, index, collection) { if (callback(value, index, collection)) { result = value; return indicatorObject; } }); return result; } /** * Iterates over a `collection`, executing the `callback` for each element in * the `collection`. The `callback` is bound to `thisArg` and invoked with three * arguments; (value, index|key, collection). Callbacks may exit iteration early * by explicitly returning `false`. * * @static * @memberOf _ * @alias each * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array|Object|String} Returns `collection`. * @example * * _([1, 2, 3]).forEach(alert).join(','); * // => alerts each number and returns '1,2,3' * * _.forEach({ 'one': 1, 'two': 2, 'three': 3 }, alert); * // => alerts each number value (order is not guaranteed) */ function forEach(collection, callback, thisArg) { if (callback && typeof thisArg == 'undefined' && isArray(collection)) { var index = -1, length = collection.length; while (++index < length) { if (callback(collection[index], index, collection) === indicatorObject) { break; } } } else { each(collection, callback, thisArg); }; } /** * Creates an object composed of keys returned from running each element of * `collection` through a `callback`. The corresponding value of each key is an * array of elements passed to `callback` that returned the key. The `callback` * is bound to `thisArg` and invoked with three arguments; (value, index|key, collection). * The `callback` argument may also be the name of a property to group by (e.g. 'length'). * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|String} callback|property The function called per iteration * or property name to group by. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Object} Returns the composed aggregate object. * @example * * _.groupBy([4.2, 6.1, 6.4], function(num) { return Math.floor(num); }); * // => { '4': [4.2], '6': [6.1, 6.4] } * * _.groupBy([4.2, 6.1, 6.4], function(num) { return this.floor(num); }, Math); * // => { '4': [4.2], '6': [6.1, 6.4] } * * _.groupBy(['one', 'two', 'three'], 'length'); * // => { '3': ['one', 'two'], '5': ['three'] } */ function groupBy(collection, callback, thisArg) { var result = {}; callback = createCallback(callback, thisArg); forEach(collection, function(value, key, collection) { key = callback(value, key, collection); (hasOwnProperty.call(result, key) ? result[key] : result[key] = []).push(value); }); return result; } /** * Invokes the method named by `methodName` on each element in the `collection`, * returning an array of the results of each invoked method. 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 in the `collection`. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @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 the results of 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(collection, methodName) { var args = slice(arguments, 2), isFunc = typeof methodName == 'function', result = []; forEach(collection, function(value) { result.push((isFunc ? methodName : value[methodName]).apply(value, args)); }); return result; } /** * Creates an array of values by running each element in the `collection` * through a `callback`. The `callback` is bound to `thisArg` and invoked with * three arguments; (value, index|key, collection). * * @static * @memberOf _ * @alias collect * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array} Returns a new array of the results of each `callback` execution. * @example * * _.map([1, 2, 3], function(num) { return num * 3; }); * // => [3, 6, 9] * * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; }); * // => [3, 6, 9] (order is not guaranteed) */ function map(collection, callback, thisArg) { var index = -1, length = collection ? collection.length : 0, result = Array(typeof length == 'number' ? length : 0); callback = createCallback(callback, thisArg); if (isArray(collection)) { while (++index < length) { result[index] = callback(collection[index], index, collection); } } else { each(collection, function(value, key, collection) { result[++index] = callback(value, key, collection); }); } return result; } /** * Retrieves the maximum value of an `array`. If `callback` is passed, * it will be executed for each value in the `array` to generate the * criterion by which the value is ranked. The `callback` is bound to * `thisArg` and invoked with three arguments; (value, index, collection). * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Mixed} Returns the maximum value. * @example * * var stooges = [ * { 'name': 'moe', 'age': 40 }, * { 'name': 'larry', 'age': 50 }, * { 'name': 'curly', 'age': 60 } * ]; * * _.max(stooges, function(stooge) { return stooge.age; }); * // => { 'name': 'curly', 'age': 60 }; */ function max(collection, callback, thisArg) { var computed = -Infinity, index = -1, length = collection ? collection.length : 0, result = computed; if (callback || !isArray(collection)) { callback = createCallback(callback, thisArg); each(collection, function(value, index, collection) { var current = callback(value, index, collection); if (current > computed) { computed = current; result = value; } }); } else { while (++index < length) { if (collection[index] > result) { result = collection[index]; } } } return result; } /** * Retrieves the minimum value of an `array`. If `callback` is passed, * it will be executed for each value in the `array` to generate the * criterion by which the value is ranked. The `callback` is bound to `thisArg` * and invoked with three arguments; (value, index, collection). * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Mixed} Returns the minimum value. * @example * * _.min([10, 5, 100, 2, 1000]); * // => 2 */ function min(collection, callback, thisArg) { var computed = Infinity, index = -1, length = collection ? collection.length : 0, result = computed; if (callback || !isArray(collection)) { callback = createCallback(callback, thisArg); each(collection, function(value, index, collection) { var current = callback(value, index, collection); if (current < computed) { computed = current; result = value; } }); } else { while (++index < length) { if (collection[index] < result) { result = collection[index]; } } } return result; } /** * Retrieves the value of a specified property from all elements in * the `collection`. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {String} property The property to pluck. * @returns {Array} Returns a new array of property values. * @example * * var stooges = [ * { 'name': 'moe', 'age': 40 }, * { 'name': 'larry', 'age': 50 }, * { 'name': 'curly', 'age': 60 } * ]; * * _.pluck(stooges, 'name'); * // => ['moe', 'larry', 'curly'] */ function pluck(collection, property) { return map(collection, property + ''); } /** * Boils down a `collection` to a single value. The initial state of the * reduction is `accumulator` and each successive step of it should be returned * by the `callback`. The `callback` is bound to `thisArg` and invoked with 4 * arguments; for arrays they are (accumulator, value, index|key, collection). * * @static * @memberOf _ * @alias foldl, inject * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [accumulator] Initial value of the accumulator. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Mixed} Returns the accumulated value. * @example * * var sum = _.reduce([1, 2, 3], function(memo, num) { return memo + num; }); * // => 6 */ function reduce(collection, callback, accumulator, thisArg) { var noaccum = arguments.length < 3; callback = createCallback(callback, thisArg, indicatorObject); if (isArray(collection)) { var index = -1, length = collection.length; if (noaccum) { accumulator = collection[++index]; } while (++index < length) { accumulator = callback(accumulator, collection[index], index, collection); } } else { each(collection, function(value, index, collection) { accumulator = noaccum ? (noaccum = false, value) : callback(accumulator, value, index, collection) }); } return accumulator; } /** * The right-associative version of `_.reduce`. * * @static * @memberOf _ * @alias foldr * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [accumulator] Initial value of the accumulator. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Mixed} Returns the accumulated value. * @example * * var list = [[0, 1], [2, 3], [4, 5]]; * var flat = _.reduceRight(list, function(a, b) { return a.concat(b); }, []); * // => [4, 5, 2, 3, 0, 1] */ function reduceRight(collection, callback, accumulator, thisArg) { var iteratee = collection, length = collection ? collection.length : 0, noaccum = arguments.length < 3; if (typeof length != 'number') { var props = keys(collection); length = props.length; } callback = createCallback(callback, thisArg, indicatorObject); forEach(collection, function(value, index, collection) { index = props ? props[--length] : --length; accumulator = noaccum ? (noaccum = false, iteratee[index]) : callback(accumulator, iteratee[index], index, collection); }); return accumulator; } /** * The opposite of `_.filter`, this method returns the values of a * `collection` that `callback` does **not** return truthy for. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array} Returns a new array of elements that did **not** pass the * callback check. * @example * * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); * // => [1, 3, 5] */ function reject(collection, callback, thisArg) { callback = createCallback(callback, thisArg); return filter(collection, function(value, index, collection) { return !callback(value, index, collection); }); } /** * Creates an array of shuffled `array` values, using a version of the * Fisher-Yates shuffle. See http://en.wikipedia.org/wiki/Fisher-Yates_shuffle. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to shuffle. * @returns {Array} Returns a new shuffled collection. * @example * * _.shuffle([1, 2, 3, 4, 5, 6]); * // => [4, 1, 6, 3, 5, 2] */ function shuffle(collection) { var index = -1, result = Array(collection ? collection.length : 0); forEach(collection, function(value) { var rand = floor(nativeRandom() * (++index + 1)); result[index] = result[rand]; result[rand] = value; }); return result; } /** * Gets the size of the `collection` by returning `collection.length` for arrays * and array-like objects or the number of own enumerable properties for objects. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to inspect. * @returns {Number} Returns `collection.length` or number of own enumerable properties. * @example * * _.size([1, 2]); * // => 2 * * _.size({ 'one': 1, 'two': 2, 'three': 3 }); * // => 3 * * _.size('curly'); * // => 5 */ function size(collection) { var length = collection ? collection.length : 0; return typeof length == 'number' ? length : keys(collection).length; } /** * Checks if the `callback` returns a truthy value for **any** element of a * `collection`. The function returns as soon as it finds passing value, and * does not iterate over the entire `collection`. The `callback` is bound to * `thisArg` and invoked with three arguments; (value, index|key, collection). * * @static * @memberOf _ * @alias any * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Boolean} Returns `true` if any element passes the callback check, * else `false`. * @example * * _.some([null, 0, 'yes', false], Boolean); * // => true */ function some(collection, callback, thisArg) { var result; callback = createCallback(callback, thisArg); if (isArray(collection)) { var index = -1, length = collection.length; while (++index < length) { if ((result = callback(collection[index], index, collection))) { break; } } } else { each(collection, function(value, index, collection) { return (result = callback(value, index, collection)) && indicatorObject; }); } return !!result; } /** * Creates an array, stable sorted in ascending order by the results of * running each element of `collection` through a `callback`. The `callback` * is bound to `thisArg` and invoked with three arguments; (value, index|key, collection). * The `callback` argument may also be the name of a property to sort by (e.g. 'length'). * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Function|String} callback|property The function called per iteration * or property name to sort by. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array} Returns a new array of sorted elements. * @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(collection, callback, thisArg) { var result = []; callback = createCallback(callback, thisArg); forEach(collection, function(value, index, collection) { result.push({ 'criteria': callback(value, index, collection), 'index': index, 'value': value }); }); var length = result.length; result.sort(compareAscending); while (length--) { result[length] = result[length].value; } return result; } /** * Converts the `collection` to an array. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to convert. * @returns {Array} Returns the new converted array. * @example * * (function() { return _.toArray(arguments).slice(1); })(1, 2, 3, 4); * // => [2, 3, 4] */ function toArray(collection) { var length = collection ? collection.length : 0; if (typeof length == 'number') { return slice(collection); } return values(collection); } /** * Examines each element in a `collection`, returning an array of all elements * that contain the given `properties`. * * @static * @memberOf _ * @category Collections * @param {Array|Object|String} collection The collection to iterate over. * @param {Object} properties The object of property values to filter by. * @returns {Array} Returns a new array of elements that contain the given `properties`. * @example * * var stooges = [ * { 'name': 'moe', 'age': 40 }, * { 'name': 'larry', 'age': 50 }, * { 'name': 'curly', 'age': 60 } * ]; * * _.where(stooges, { 'age': 40 }); * // => [{ 'name': 'moe', 'age': 40 }] */ function where(collection, properties) { var props = keys(properties); return filter(collection, function(object) { var length = props.length; while (length--) { var result = object[props[length]] === properties[props[length]]; if (!result) { break; } } return !!result; }); } /*--------------------------------------------------------------------------*/ /** * Creates an array with all falsey values of `array` removed. The values * `false`, `null`, `0`, `""`, `undefined` and `NaN` are all falsey. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to compact. * @returns {Array} Returns a new filtered array. * @example * * _.compact([0, 1, false, 2, '', 3]); * // => [1, 2, 3] */ function compact(array) { var index = -1, length = array ? array.length : 0, result = []; while (++index < length) { var value = array[index]; if (value) { result.push(value); } } return result; } /** * Creates an array of `array` elements not present in the other arrays * using strict equality for comparisons, i.e. `===`. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to process. * @param {Array} [array1, array2, ...] Arrays to check. * @returns {Array} Returns a new array of `array` elements not present in the * other arrays. * @example * * _.difference([1, 2, 3, 4, 5], [5, 2, 10]); * // => [1, 3, 4] */ function difference(array) { var index = -1, length = array.length, flattened = concat.apply(arrayRef, arguments), result = []; while (++index < length) { var value = array[index] if (indexOf(flattened, value, length) < 0) { result.push(value); } } return result } /** * Gets the first element of the `array`. Pass `n` to return the first `n` * elements of the `array`. * * @static * @memberOf _ * @alias head, take * @category Arrays * @param {Array} array The array to query. * @param {Number} [n] The number of elements to return. * @param- {Object} [guard] 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 element, or an array of the first `n` * elements, of `array`. * @example * * _.first([5, 4, 3, 2, 1]); * // => 5 */ function first(array, n, guard) { if (array) { var length = array.length; return (n == null || guard) ? array[0] : slice(array, 0, nativeMin(nativeMax(0, n), length)); } } /** * Flattens a nested array (the nesting can be to any depth). If `shallow` is * truthy, `array` will only be flattened a single level. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to compact. * @param {Boolean} shallow A flag to indicate only flattening a single level. * @returns {Array} Returns a new flattened array. * @example * * _.flatten([1, [2], [3, [[4]]]]); * // => [1, 2, 3, 4]; * * _.flatten([1, [2], [3, [[4]]]], true); * // => [1, 2, 3, [[4]]]; */ function flatten(array, shallow) { var index = -1, length = array ? array.length : 0, result = []; while (++index < length) { var value = array[index]; // recursively flatten arrays (susceptible to call stack limits) if (isArray(value)) { push.apply(result, shallow ? value : flatten(value)); } else { result.push(value); } } return result; } /** * 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 `fromIndex` will run a faster binary search. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to search. * @param {Mixed} value The value to search for. * @param {Boolean|Number} [fromIndex=0] The index to search 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, 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, fromIndex) { var index = -1, length = array ? array.length : 0; if (typeof fromIndex == 'number') { index = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0) - 1; } else if (fromIndex) { index = sortedIndex(array, value); return array[index] === value ? index : -1; } while (++index < length) { if (array[index] === value) { return index; } } return -1; } /** * Gets all but the last element of `array`. Pass `n` to exclude the last `n` * elements from the result. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to query. * @param {Number} [n=1] The number of elements to exclude. * @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 element, or `n` elements, of `array`. * @example * * _.initial([3, 2, 1]); * // => [3, 2] */ function initial(array, n, guard) { if (!array) { return []; } var length = array.length; n = n == null || guard ? 1 : n || 0; return slice(array, 0, nativeMin(nativeMax(0, length - n), length)); } /** * Computes the intersection of all the passed-in arrays using strict equality * for comparisons, i.e. `===`. * * @static * @memberOf _ * @category Arrays * @param {Array} [array1, array2, ...] Arrays to process. * @returns {Array} Returns a new array of unique elements that are present * in **all** of the arrays. * @example * * _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]); * // => [1, 2] */ function intersection(array) { var args = arguments, argsLength = args.length, index = -1, length = array ? array.length : 0, result = []; outer: while (++index < length) { var value = array[index]; if (indexOf(result, value) < 0) { var argsIndex = argsLength; while (--argsIndex) { if (indexOf(args[argsIndex], value) < 0) { continue outer; } } result.push(value); } } return result; } /** * Gets the last element of the `array`. Pass `n` to return the last `n` * elements of the `array`. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to query. * @param {Number} [n] The number of elements to return. * @param- {Object} [guard] Internally used to allow this method to work with * others like `_.map` without using their callback `index` argument for `n`. * @returns {Mixed} Returns the last element, or an array of the last `n` * elements, of `array`. * @example * * _.last([3, 2, 1]); * // => 1 */ function last(array, n, guard) { if (array) { var length = array.length; return (n == null || guard) ? array[length - 1] : slice(array, nativeMax(0, length - n)); } } /** * Gets the index at which the last occurrence of `value` is found using strict * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used * as the offset from the end of the collection. * * @static * @memberOf _ * @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 search 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, fromIndex) { var index = array ? array.length : 0; if (typeof fromIndex == 'number') { index = (fromIndex < 0 ? nativeMax(0, index + fromIndex) : nativeMin(fromIndex, index - 1)) + 1; } while (index--) { if (array[index] === value) { return index; } } return -1; } /** * Creates an object composed from arrays of `keys` and `values`. Pass either * a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`, or * two arrays, one of `keys` and one of corresponding `values`. * * @static * @memberOf _ * @category Arrays * @param {Array} keys The array of keys. * @param {Array} [values=[]] The array of values. * @returns {Object} Returns an object composed of the given keys and * corresponding values. * @example * * _.object(['moe', 'larry', 'curly'], [30, 40, 50]); * // => { 'moe': 30, 'larry': 40, 'curly': 50 } */ function object(keys, values) { var index = -1, length = keys ? keys.length : 0, result = {}; while (++index < length) { var key = keys[index]; if (values) { result[key] = values[index]; } else { result[key[0]] = key[1]; } } 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. * * @static * @memberOf _ * @category Arrays * @param {Number} [start=0] The start of the range. * @param {Number} end The end of the range. * @param {Number} [step=1] The value to increment or descrement by. * @returns {Array} Returns a new range array. * @example * * _.range(10); * // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] * * _.range(1, 11); * // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] * * _.range(0, 30, 5); * // => [0, 5, 10, 15, 20, 25] * * _.range(0, -10, -1); * // => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] * * _.range(0); * // => [] */ function range(start, end, step) { start = +start || 0; step = +step || 1; if (end == null) { end = start; start = 0; } // use `Array(length)` so V8 will avoid the slower "dictionary" mode // http://youtu.be/XAqIpGU8ZZk#t=17m25s var index = -1, length = nativeMax(0, ceil((end - start) / step)), result = Array(length); while (++index < length) { result[index] = start; start += step; } return result; } /** * The opposite of `_.initial`, this method gets all but the first value of * `array`. Pass `n` to exclude the first `n` values from the result. * * @static * @memberOf _ * @alias drop, tail * @category Arrays * @param {Array} array The array to query. * @param {Number} [n=1] The number of elements to exclude. * @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 element, or `n` elements, of `array`. * @example * * _.rest([3, 2, 1]); * // => [2, 1] */ function rest(array, n, guard) { return slice(array, (n == null || guard) ? 1 : nativeMax(0, n)); } /** * 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 one argument; (value). The `callback` * argument may also be the name of a property to order by. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to iterate over. * @param {Mixed} value The value to evaluate. * @param {Function|String} [callback=identity|property] The function called * per iteration or property name to order by. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Number} Returns the index at which the value should be inserted * into `array`. * @example * * _.sortedIndex([20, 30, 50], 40); * // => 2 * * _.sortedIndex([{ 'x': 20 }, { 'x': 30 }, { 'x': 50 }], { 'x': 40 }, 'x'); * // => 2 * * var dict = { * 'wordToNumber': { 'twenty': 20, 'thirty': 30, 'fourty': 40, 'fifty': 50 } * }; * * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) { * return dict.wordToNumber[word]; * }); * // => 2 * * _.sortedIndex(['twenty', 'thirty', 'fifty'], 'fourty', function(word) { * return this.wordToNumber[word]; * }, dict); * // => 2 */ function sortedIndex(array, value, callback, thisArg) { var low = 0, high = array ? array.length : low; // explicitly reference `identity` for better inlining in Firefox callback = callback ? createCallback(callback, thisArg) : identity; value = callback(value); while (low < high) { var mid = (low + high) >>> 1; callback(array[mid]) < value ? low = mid + 1 : high = mid; } return low; } /** * Computes the union of the passed-in arrays using strict equality for * comparisons, i.e. `===`. * * @static * @memberOf _ * @category Arrays * @param {Array} [array1, array2, ...] Arrays to process. * @returns {Array} Returns a new array of unique values, in order, that are * present in one or more of the arrays. * @example * * _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]); * // => [1, 2, 3, 101, 10] */ function union() { return uniq(concat.apply(arrayRef, arguments)); } /** * Creates 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 * element of `array` is passed through a callback` before uniqueness is computed. * The `callback` is bound to `thisArg` and invoked with three arguments; (value, index, array). * * @static * @memberOf _ * @alias unique * @category Arrays * @param {Array} array The array to process. * @param {Boolean} [isSorted=false] A flag to indicate that the `array` is already sorted. * @param {Function} [callback=identity] The function called per iteration. * @param {Mixed} [thisArg] The `this` binding of `callback`. * @returns {Array} Returns a duplicate-value-free array. * @example * * _.uniq([1, 2, 1, 3, 1]); * // => [1, 2, 3] * * _.uniq([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, thisArg) { var index = -1, length = array ? array.length : 0, result = [], seen = result; if (typeof isSorted == 'function') { thisArg = callback; callback = isSorted; isSorted = false; } if (callback) { seen = []; callback = createCallback(callback, thisArg); } while (++index < length) { var value = array[index], computed = callback ? callback(value, index, array) : value; if (isSorted ? !index || seen[seen.length - 1] !== computed : indexOf(seen, computed) < 0 ) { if (callback) { seen.push(computed); } result.push(value); } } return result; } /** * Creates an array with all occurrences of the passed values removed using * strict equality for comparisons, i.e. `===`. * * @static * @memberOf _ * @category Arrays * @param {Array} array The array to filter. * @param {Mixed} [value1, value2, ...] Values to remove. * @returns {Array} Returns a new filtered array. * @example * * _.without([1, 2, 1, 0, 3, 1, 4], 0, 1); * // => [2, 3, 4] */ function without(array) { var index = -1, length = array.length, result = []; while (++index < length) { var value = array[index] if (indexOf(arguments, value, 1) < 0) { result.push(value); } } return result } /** * Groups the elements of each array at their corresponding indexes. Useful for * separate data sources that are coordinated through matching array indexes. * For a matrix of nested arrays, `_.zip.apply(...)` can transpose the matrix * in a similar fashion. * * @static * @memberOf _ * @category Arrays * @param {Array} [array1, array2, ...] Arrays to process. * @returns {Array} Returns a new array of grouped elements. * @example * * _.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]); * // => [['moe', 30, true], ['larry', 40, false], ['curly', 50, false]] */ function zip(array) { var index = -1, length = array ? max(pluck(arguments, 'length')) : 0, result = Array(length); while (++index < length) { result[index] = pluck(arguments, index); } return result; } /*--------------------------------------------------------------------------*/ /** * Creates a function that is restricted to executing `func` only after it is * called `n` times. The `func` is executed with the `this` binding of the * created function. * * @static * @memberOf _ * @category Functions * @param {Number} n The number of times the function must be called before * it is executed. * @param {Function} func The function to restrict. * @returns {Function} Returns the new restricted function. * @example * * var renderNotes = _.after(notes.length, render); * _.forEach(notes, function(note) { * note.asyncSave({ 'success': renderNotes }); * }); * // `renderNotes` is run once, after all notes have saved */ function after(n, func) { if (n < 1) { return func(); } return function() { if (--n < 1) { return func.apply(this, arguments); } }; } /** * Creates a function that, when called, invokes `func` with the `this` * binding of `thisArg` and prepends any additional `bind` arguments to those * passed to the bound function. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to bind. * @param {Mixed} [thisArg] The `this` binding of `func`. * @param {Mixed} [arg1, arg2, ...] Arguments to be partially applied. * @returns {Function} Returns the new bound function. * @example * * var func = function(greeting) { * return greeting + ' ' + this.name; * }; * * func = _.bind(func, { 'name': 'moe' }, 'hi'); * func(); * // => 'hi moe' */ function bind(func, thisArg) { // use `Function#bind` if it exists and is fast // (in V8 `Function#bind` is slower except when partially applied) return isBindFast || (nativeBind && arguments.length > 2) ? nativeBind.call.apply(nativeBind, arguments) : createBound(func, thisArg, slice(arguments, 2)); } /** * 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 * @memberOf _ * @category Functions * @param {Object} object The object to bind and assign the bound methods to. * @param {String} [methodName1, methodName2, ...] Method names on the object to bind. * @returns {Object} Returns `object`. * @example * * var buttonView = { * 'label': 'lodash', * 'onClick': function() { alert('clicked: ' + this.label); } * }; * * _.bindAll(buttonView); * jQuery('#lodash_button').on('click', buttonView.onClick); * // => When the button is clicked, `this.label` will have the correct value */ function bindAll(object) { var funcs = arguments, index = funcs.length > 1 ? 0 : (funcs = functions(object), -1), length = funcs.length; while (++index < length) { var key = funcs[index]; object[key] = bind(object[key], object); } return object; } /** * Creates a 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 the functions `f()`, `g()`, and `h()` produces `f(g(h()))`. * Each function is executed with the `this` binding of the composed function. * * @static * @memberOf _ * @category Functions * @param {Function} [func1, func2, ...] Functions to compose. * @returns {Function} Returns the new composed function. * @example * * var greet = function(name) { return 'hi: ' + name; }; * var exclaim = function(statement) { return statement + '!'; }; * var welcome = _.compose(exclaim, greet); * welcome('moe'); * // => 'hi: moe!' */ function compose() { var funcs = arguments; return function() { var args = arguments, length = funcs.length; while (length--) { args = [funcs[length].apply(this, args)]; } return args[0]; }; } /** * Creates a function that will delay the execution of `func` until after * `wait` milliseconds have elapsed since the last time it was invoked. Pass * `true` for `immediate` to cause debounce to invoke `func` on the leading, * instead of the trailing, edge of the `wait` timeout. Subsequent calls to * the debounced function will return the result of the last `func` call. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to debounce. * @param {Number} wait The number of milliseconds to delay. * @param {Boolean} immediate A flag to indicate execution is on the leading * edge of the timeout. * @returns {Function} Returns the new debounced function. * @example * * var lazyLayout = _.debounce(calculateLayout, 300); * jQuery(window).on('resize', lazyLayout); */ function debounce(func, wait, immediate) { var args, result, thisArg, timeoutId; function delayed() { timeoutId = null; if (!immediate) { result = func.apply(thisArg, args); } } return function() { var isImmediate = immediate && !timeoutId; args = arguments; thisArg = this; clearTimeout(timeoutId); timeoutId = setTimeout(delayed, wait); if (isImmediate) { result = func.apply(thisArg, args); } return result; }; } /** * Executes the `func` function after `wait` milliseconds. Additional arguments * will be passed to `func` when it is invoked. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to delay. * @param {Number} wait The number of milliseconds to delay execution. * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with. * @returns {Number} Returns the `setTimeout` timeout id. * @example * * var log = _.bind(console.log, console); * _.delay(log, 1000, 'logged later'); * // => 'logged later' (Appears after one second.) */ function delay(func, wait) { var args = slice(arguments, 2); return setTimeout(function() { func.apply(undefined, args); }, wait); } /** * Defers executing the `func` function until the current call stack has cleared. * Additional arguments will be passed to `func` when it is invoked. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to defer. * @param {Mixed} [arg1, arg2, ...] Arguments to invoke the function with. * @returns {Number} Returns the `setTimeout` timeout id. * @example * * _.defer(function() { alert('deferred'); }); * // returns from the function before `alert` is called */ function defer(func) { var args = slice(arguments, 1); return setTimeout(function() { func.apply(undefined, args); }, 1); } /** * Creates a function that memoizes the result of `func`. If `resolver` is * passed, it will be used to determine the cache key for storing the result * based on the arguments passed to the memoized function. By default, the first * argument passed to the memoized function is used as the cache key. The `func` * is executed with the `this` binding of the memoized function. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to have its output memoized. * @param {Function} [resolver] A function used to resolve the cache key. * @returns {Function} Returns the new memoizing function. * @example * * var fibonacci = _.memoize(function(n) { * return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2); * }); */ function memoize(func, resolver) { var cache = {}; return function() { var key = resolver ? resolver.apply(this, arguments) : arguments[0]; return hasOwnProperty.call(cache, key) ? cache[key] : (cache[key] = func.apply(this, arguments)); }; } /** * Creates a function that is restricted to execute `func` once. Repeat calls to * the function will return the value of the first call. The `func` is executed * with the `this` binding of the created function. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to restrict. * @returns {Function} Returns the new restricted function. * @example * * var initialize = _.once(createApplication); * initialize(); * initialize(); * // Application is only created once. */ function once(func) { var result, ran = false; return function() { if (ran) { return result; } ran = true; result = func.apply(this, arguments); // clear the `func` variable so the function may be garbage collected func = null; return result; }; } /** * Creates a function that, when executed, will only call the `func` * function at most once per every `wait` milliseconds. If the throttled * function is invoked more than once during the `wait` timeout, `func` will * also be called on the trailing edge of the timeout. Subsequent calls to the * throttled function will return the result of the last `func` call. * * @static * @memberOf _ * @category Functions * @param {Function} func The function to throttle. * @param {Number} wait The number of milliseconds to throttle executions to. * @returns {Function} Returns the new throttled function. * @example * * var throttled = _.throttle(updatePosition, 100); * jQuery(window).on('scroll', throttled); */ function throttle(func, wait) { var args, result, thisArg, timeoutId, lastCalled = 0; function trailingCall() { lastCalled = new Date; timeoutId = null; result = func.apply(thisArg, args); } return function() { var now = new Date, remaining = wait - (now - lastCalled); args = arguments; thisArg = this; if (remaining <= 0) { clearTimeout(timeoutId); timeoutId = null; lastCalled = now; result = func.apply(thisArg, args); } else if (!timeoutId) { timeoutId = setTimeout(trailingCall, remaining); } return result; }; } /** * Creates a function that passes `value` to the `wrapper` function as its * first argument. Additional arguments passed to the function are appended * to those passed to the `wrapper` function. The `wrapper` is executed with * the `this` binding of the created function. * * @static * @memberOf _ * @category Functions * @param {Mixed} value The value to wrap. * @param {Function} wrapper The wrapper function. * @returns {Function} Returns the new function. * @example * * var hello = function(name) { return 'hello ' + name; }; * hello = _.wrap(hello, function(func) { * return 'before, ' + func('moe') + ', after'; * }); * hello(); * // => 'before, hello moe, after' */ function wrap(value, wrapper) { return function() { var args = [value]; push.apply(args, arguments); return wrapper.apply(this, args); }; } /*--------------------------------------------------------------------------*/ /** * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their * corresponding HTML entities. * * @static * @memberOf _ * @category Utilities * @param {String} string The string to escape. * @returns {String} Returns the escaped string. * @example * * _.escape('Moe, Larry & Curly'); * // => 'Moe, Larry & Curly' */ function escape(string) { return string == null ? '' : (string + '').replace(reUnescapedHtml, escapeHtmlChar); } /** * This function returns the first argument passed to it. * * @static * @memberOf _ * @category Utilities * @param {Mixed} value Any value. * @returns {Mixed} Returns `value`. * @example * * var moe = { 'name': 'moe' }; * moe === _.identity(moe); * // => true */ function identity(value) { return value; } /** * Adds functions properties of `object` to the `lodash` function and chainable * wrapper. * * @static * @memberOf _ * @category Utilities * @param {Object} object The object of function properties to add to `lodash`. * @example * * _.mixin({ * 'capitalize': function(string) { * return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase(); * } * }); * * _.capitalize('larry'); * // => 'Larry' * * _('curly').capitalize(); * // => 'Curly' */ function mixin(object) { forEach(functions(object), function(methodName) { var func = lodash[methodName] = object[methodName]; lodash.prototype[methodName] = function() { var args = [this.__wrapped__]; push.apply(args, arguments); var result = func.apply(lodash, args); if (this.__chain__) { result = new lodash(result); result.__chain__ = true; } return result; }; }); } /** * Reverts the '_' variable to its previous value and returns a reference to * the `lodash` function. * * @static * @memberOf _ * @category Utilities * @returns {Function} Returns the `lodash` function. * @example * * var lodash = _.noConflict(); */ function noConflict() { window._ = oldDash; return this; } /** * Produces a random number between `min` and `max` (inclusive). If only one * argument is passed, a number between `0` and the given number will be returned. * * @static * @memberOf _ * @category Utilities * @param {Number} [min=0] The minimum possible value. * @param {Number} [max=1] The maximum possible value. * @returns {Number} Returns a random number. * @example * * _.random(0, 5); * // => a number between 1 and 5 * * _.random(5); * // => also a number between 1 and 5 */ function random(min, max) { if (min == null && max == null) { max = 1; } min = +min || 0; if (max == null) { max = min; min = 0; } return min + floor(nativeRandom() * ((+max || 0) - min + 1)); } /** * 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. If `object` is falsey, then `null` is returned. * * @static * @memberOf _ * @category Utilities * @param {Object} object The object to inspect. * @param {String} property The property to get the value of. * @returns {Mixed} Returns the resolved value. * @example * * var object = { * 'cheese': 'crumpets', * 'stuff': function() { * return 'nonsense'; * } * }; * * _.result(object, 'cheese'); * // => 'crumpets' * * _.result(object, 'stuff'); * // => 'nonsense' */ function result(object, property) { // based on Backbone's private `getValue` function // https://github.com/documentcloud/backbone/blob/0.9.2/backbone.js#L1419-1424 var value = object ? object[property] : null; return isFunction(value) ? object[property]() : value; } /** * A micro-templating method that handles arbitrary delimiters, preserves * whitespace, and correctly escapes quotes within interpolated code. * * Note: In the development build `_.template` utilizes sourceURLs for easier * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl * * Note: Lo-Dash may be used in Chrome extensions by either creating a `lodash csp` * build and avoiding `_.template` use, or loading Lo-Dash in a sandboxed page. * See http://developer.chrome.com/trunk/extensions/sandboxingEval.html * * @static * @memberOf _ * @category Utilities * @param {String} text The template text. * @param {Obect} data The data object used to populate the text. * @param {Object} options The options object. * escape - The "escape" delimiter regexp. * evaluate - The "evaluate" delimiter regexp. * interpolate - The "interpolate" delimiter regexp. * sourceURL - The sourceURL of the template's compiled source. * variable - The data object variable name. * * @returns {Function|String} Returns a compiled function when no `data` object * is given, else it returns the interpolated text. * @example * * // using a compiled template * var compiled = _.template('hello <%= name %>'); * compiled({ 'name': 'moe' }); * // => 'hello moe' * * var list = '<% _.forEach(people, function(name) { %>
  • <%= name %>
  • <% }); %>'; * _.template(list, { 'people': ['moe', 'larry', 'curly'] }); * // => '
  • moe
  • larry
  • curly
  • ' * * // using the "escape" delimiter to escape HTML in data property values * _.template('<%- value %>', { 'value': '