From 8a5c46da2b3d5e325fc96ef5eed1f451c925cf50 Mon Sep 17 00:00:00 2001 From: Tyler Renelle Date: Sat, 14 Dec 2013 11:33:11 -0700 Subject: [PATCH] classes: fix item & stat loss on death bugs --- dist/habitrpg-shared.js | 2003 ++++++++++++++++++++++++--------------- package.json | 4 +- script/index.coffee | 16 +- 3 files changed, 1224 insertions(+), 799 deletions(-) diff --git a/dist/habitrpg-shared.js b/dist/habitrpg-shared.js index b2cbae043c..9c92fe722f 100644 --- a/dist/habitrpg-shared.js +++ b/dist/habitrpg-shared.js @@ -65,7 +65,7 @@ process.chdir = function (dir) { },{}],3:[function(require,module,exports){ var global=self;/** * @license - * Lo-Dash 2.2.1 (Custom Build) + * Lo-Dash 2.4.1 (Custom Build) * Build: `lodash modern -o ./dist/lodash.js` * Copyright 2012-2013 The Dojo Foundation * Based on Underscore.js 1.5.2 @@ -112,7 +112,7 @@ var global=self;/** /** * Used to match ES6 template delimiters - * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-7.8.6 + * http://people.mozilla.org/~jorendorff/es6-draft.html#sec-literals-string-literals */ var reEsTemplate = /\$\{([^\\}]*(?:\\.[^\\}]*)*)\}/g; @@ -120,7 +120,7 @@ var global=self;/** var reFlags = /\w*$/; /** Used to detected named functions */ - var reFuncName = /^function[ \n\r\t]+\w/; + var reFuncName = /^\s*function[ \n\r\t]+\w/; /** Used to match "interpolate" template delimiters */ var reInterpolate = /<%=([\s\S]+?)%>/g; @@ -141,7 +141,7 @@ var global=self;/** var contextProps = [ 'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object', 'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN', - 'parseInt', 'setImmediate', 'setTimeout' + 'parseInt', 'setTimeout' ]; /** Used to make template sourceURLs easier to identify */ @@ -321,22 +321,29 @@ var global=self;/** */ function compareAscending(a, b) { var ac = a.criteria, - bc = b.criteria; + bc = b.criteria, + index = -1, + length = ac.length; - // ensure a stable sort in V8 and other engines - // http://code.google.com/p/v8/issues/detail?id=90 - if (ac !== bc) { - if (ac > bc || typeof ac == 'undefined') { - return 1; - } - if (ac < bc || typeof bc == 'undefined') { - return -1; + while (++index < length) { + var value = ac[index], + other = bc[index]; + + if (value !== other) { + if (value > other || typeof value == 'undefined') { + return 1; + } + if (value < other || typeof other == 'undefined') { + return -1; + } } } - // The JS engine embedded in Adobe applications like InDesign has a buggy - // `Array#sort` implementation that causes it, under certain circumstances, - // to return the same value for `a` and `b`. - // See https://github.com/jashkenas/underscore/pull/1247 + // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications + // that causes it, under certain circumstances, to return the same value for + // `a` and `b`. See https://github.com/jashkenas/underscore/pull/1247 + // + // This also ensures a stable sort in V8 and other engines. + // See http://code.google.com/p/v8/issues/detail?id=90 return a.index - b.index; } @@ -418,15 +425,6 @@ var global=self;/** }; } - /** - * A no-operation function. - * - * @private - */ - function noop() { - // no operation performed - } - /** * Releases the given array back to the array pool. * @@ -529,11 +527,14 @@ var global=self;/** /** Used to restore the original `_` reference in `noConflict` */ var oldDash = context._; + /** Used to resolve the internal [[Class]] of values */ + var toString = objectProto.toString; + /** Used to detect if a method is native */ var reNative = RegExp('^' + - String(objectProto.valueOf) + String(toString) .replace(/[.*+?^${}()|[\]\\]/g, '\\$&') - .replace(/valueOf|for [^\]]+/g, '.+?') + '$' + .replace(/toString| for [^\]]+/g, '.*?') + '$' ); /** Native method shortcuts */ @@ -541,41 +542,34 @@ var global=self;/** clearTimeout = context.clearTimeout, floor = Math.floor, fnToString = Function.prototype.toString, - getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf, + getPrototypeOf = isNative(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf, hasOwnProperty = objectProto.hasOwnProperty, - now = reNative.test(now = Date.now) && now || function() { return +new Date; }, push = arrayRef.push, - setImmediate = context.setImmediate, setTimeout = context.setTimeout, splice = arrayRef.splice, - toString = objectProto.toString, unshift = arrayRef.unshift; + /** Used to set meta data on functions */ var defineProperty = (function() { + // IE 8 only accepts DOM elements try { var o = {}, - func = reNative.test(func = Object.defineProperty) && func, + func = isNative(func = Object.defineProperty) && func, result = func(o, o, o) && func; } catch(e) { } return result; }()); /* Native method shortcuts for methods with the same name as other `lodash` methods */ - var nativeBind = reNative.test(nativeBind = toString.bind) && nativeBind, - nativeCreate = reNative.test(nativeCreate = Object.create) && nativeCreate, - nativeIsArray = reNative.test(nativeIsArray = Array.isArray) && nativeIsArray, + var nativeCreate = isNative(nativeCreate = Object.create) && nativeCreate, + nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray, nativeIsFinite = context.isFinite, nativeIsNaN = context.isNaN, - nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys, + nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys, nativeMax = Math.max, nativeMin = Math.min, nativeParseInt = context.parseInt, - nativeRandom = Math.random, - nativeSlice = arrayRef.slice; - - /** Detect various environments */ - var isIeOpera = reNative.test(context.attachEvent), - isV8 = nativeBind && !/\n|true/.test(nativeBind + isIeOpera); + nativeRandom = Math.random; /** Used to lookup a built-in constructor by [[Class]] */ var ctorByClass = {}; @@ -603,15 +597,16 @@ var global=self;/** * * The chainable wrapper functions are: * `after`, `assign`, `bind`, `bindAll`, `bindKey`, `chain`, `compact`, - * `compose`, `concat`, `countBy`, `createCallback`, `curry`, `debounce`, - * `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`, `forEach`, - * `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `functions`, - * `groupBy`, `indexBy`, `initial`, `intersection`, `invert`, `invoke`, `keys`, - * `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`, `once`, `pairs`, - * `partial`, `partialRight`, `pick`, `pluck`, `pull`, `push`, `range`, `reject`, - * `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, `sortBy`, `splice`, - * `tap`, `throttle`, `times`, `toArray`, `transform`, `union`, `uniq`, `unshift`, - * `unzip`, `values`, `where`, `without`, `wrap`, and `zip` + * `compose`, `concat`, `countBy`, `create`, `createCallback`, `curry`, + * `debounce`, `defaults`, `defer`, `delay`, `difference`, `filter`, `flatten`, + * `forEach`, `forEachRight`, `forIn`, `forInRight`, `forOwn`, `forOwnRight`, + * `functions`, `groupBy`, `indexBy`, `initial`, `intersection`, `invert`, + * `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`, + * `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `pull`, `push`, + * `range`, `reject`, `remove`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, + * `sortBy`, `splice`, `tap`, `throttle`, `times`, `toArray`, `transform`, + * `union`, `uniq`, `unshift`, `unzip`, `values`, `where`, `without`, `wrap`, + * and `zip` * * The non-chainable wrapper functions are: * `clone`, `cloneDeep`, `contains`, `escape`, `every`, `find`, `findIndex`, @@ -685,14 +680,6 @@ var global=self;/** */ var support = lodash.support = {}; - /** - * Detect if `Function#bind` exists and is inferred to be fast (all but V8). - * - * @memberOf _.support - * @type boolean - */ - support.fastBind = nativeBind && !isV8; - /** * Detect if functions can be decompiled by `Function#toString` * (all but PS3 and older Opera mobile browsers & avoided in Windows 8 apps). @@ -700,7 +687,7 @@ var global=self;/** * @memberOf _.support * @type boolean */ - support.funcDecomp = !reNative.test(context.WinRTError) && reThis.test(runInContext); + support.funcDecomp = !isNative(context.WinRTError) && reThis.test(runInContext); /** * Detect if `Function#name` is supported (all but IE). @@ -773,19 +760,56 @@ var global=self;/** /*--------------------------------------------------------------------------*/ + /** + * The base implementation of `_.bind` that creates the bound function and + * sets its meta data. + * + * @private + * @param {Array} bindData The bind data array. + * @returns {Function} Returns the new bound function. + */ + function baseBind(bindData) { + var func = bindData[0], + partialArgs = bindData[2], + thisArg = bindData[4]; + + function bound() { + // `Function#bind` spec + // http://es5.github.io/#x15.3.4.5 + if (partialArgs) { + // avoid `arguments` object deoptimizations by using `slice` instead + // of `Array.prototype.slice.call` and not assigning `arguments` to a + // variable as a ternary expression + var args = slice(partialArgs); + push.apply(args, arguments); + } + // mimic the constructor's `return` behavior + // http://es5.github.io/#x13.2.2 + if (this instanceof bound) { + // ensure `new bound` is an instance of `func` + var thisBinding = baseCreate(func.prototype), + result = func.apply(thisBinding, args || arguments); + return isObject(result) ? result : thisBinding; + } + return func.apply(thisArg, args || arguments); + } + setBindData(bound, bindData); + return bound; + } + /** * The base implementation of `_.clone` without argument juggling or support * for `thisArg` binding. * * @private * @param {*} value The value to clone. - * @param {boolean} [deep=false] Specify a deep clone. + * @param {boolean} [isDeep=false] Specify a deep clone. * @param {Function} [callback] The function to customize cloning values. * @param {Array} [stackA=[]] Tracks traversed source objects. * @param {Array} [stackB=[]] Associates clones with source counterparts. * @returns {*} Returns the cloned value. */ - function baseClone(value, deep, callback, stackA, stackB) { + function baseClone(value, isDeep, callback, stackA, stackB) { if (callback) { var result = callback(value); if (typeof result != 'undefined') { @@ -818,7 +842,7 @@ var global=self;/** return value; } var isArr = isArray(value); - if (deep) { + if (isDeep) { // check for circular references and return corresponding clone var initedStack = !stackA; stackA || (stackA = getArray()); @@ -845,7 +869,7 @@ var global=self;/** } } // exit for shallow clone - if (!deep) { + if (!isDeep) { return result; } // add the source value to the stack of traversed objects @@ -855,7 +879,7 @@ var global=self;/** // recursively populate clone (susceptible to call stack limits) (isArr ? forEach : forOwn)(value, function(objValue, key) { - result[key] = baseClone(objValue, deep, callback, stackA, stackB); + result[key] = baseClone(objValue, isDeep, callback, stackA, stackB); }); if (initedStack) { @@ -865,6 +889,32 @@ var global=self;/** return result; } + /** + * The base implementation of `_.create` without support for assigning + * properties to the created object. + * + * @private + * @param {Object} prototype The object to inherit from. + * @returns {Object} Returns the new object. + */ + function baseCreate(prototype, properties) { + return isObject(prototype) ? nativeCreate(prototype) : {}; + } + // fallback for browsers without `Object.create` + if (!nativeCreate) { + baseCreate = (function() { + function Object() {} + return function(prototype) { + if (isObject(prototype)) { + Object.prototype = prototype; + var result = new Object; + Object.prototype = null; + } + return result || context.Object(); + }; + }()); + } + /** * The base implementation of `_.createCallback` without support for creating * "_.pluck" or "_.where" style callbacks. @@ -879,24 +929,30 @@ var global=self;/** if (typeof func != 'function') { return identity; } - // exit early if there is no `thisArg` - if (typeof thisArg == 'undefined') { + // exit early for no `thisArg` or already bound by `Function#bind` + if (typeof thisArg == 'undefined' || !('prototype' in func)) { return func; } - var bindData = func.__bindData__ || (support.funcNames && !func.name); + var bindData = func.__bindData__; if (typeof bindData == 'undefined') { - var source = reThis && fnToString.call(func); - if (!support.funcNames && source && !reFuncName.test(source)) { - bindData = true; + if (support.funcNames) { + bindData = !func.name; } - if (support.funcNames || !bindData) { - // checks if `func` references the `this` keyword and stores the result - bindData = !support.funcDecomp || reThis.test(source); - setBindData(func, bindData); + bindData = bindData || !support.funcDecomp; + if (!bindData) { + var source = fnToString.call(func); + if (!support.funcNames) { + bindData = !reFuncName.test(source); + } + if (!bindData) { + // checks if `func` references the `this` keyword and stores the result + bindData = reThis.test(source); + setBindData(func, bindData); + } } } // exit early if there are no `this` references or `func` is bound - if (bindData !== true && (bindData && bindData[1] & 1)) { + if (bindData === false || (bindData !== true && bindData[1] & 1)) { return func; } switch (argCount) { @@ -916,6 +972,96 @@ var global=self;/** return bind(func, thisArg); } + /** + * The base implementation of `createWrapper` that creates the wrapper and + * sets its meta data. + * + * @private + * @param {Array} bindData The bind data array. + * @returns {Function} Returns the new function. + */ + function baseCreateWrapper(bindData) { + var func = bindData[0], + bitmask = bindData[1], + partialArgs = bindData[2], + partialRightArgs = bindData[3], + thisArg = bindData[4], + arity = bindData[5]; + + var isBind = bitmask & 1, + isBindKey = bitmask & 2, + isCurry = bitmask & 4, + isCurryBound = bitmask & 8, + key = func; + + function bound() { + var thisBinding = isBind ? thisArg : this; + if (partialArgs) { + var args = slice(partialArgs); + push.apply(args, arguments); + } + if (partialRightArgs || isCurry) { + args || (args = slice(arguments)); + if (partialRightArgs) { + push.apply(args, partialRightArgs); + } + if (isCurry && args.length < arity) { + bitmask |= 16 & ~32; + return baseCreateWrapper([func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity]); + } + } + args || (args = arguments); + if (isBindKey) { + func = thisBinding[key]; + } + if (this instanceof bound) { + thisBinding = baseCreate(func.prototype); + var result = func.apply(thisBinding, args); + return isObject(result) ? result : thisBinding; + } + return func.apply(thisBinding, args); + } + setBindData(bound, bindData); + return bound; + } + + /** + * The base implementation of `_.difference` that accepts a single array + * of values to exclude. + * + * @private + * @param {Array} array The array to process. + * @param {Array} [values] The array of values to exclude. + * @returns {Array} Returns a new array of filtered values. + */ + function baseDifference(array, values) { + var index = -1, + indexOf = getIndexOf(), + length = array ? array.length : 0, + isLarge = length >= largeArraySize && indexOf === baseIndexOf, + result = []; + + if (isLarge) { + var cache = createCache(values); + if (cache) { + indexOf = cacheIndexOf; + values = cache; + } else { + isLarge = false; + } + } + while (++index < length) { + var value = array[index]; + if (indexOf(values, value) < 0) { + result.push(value); + } + } + if (isLarge) { + releaseObject(values); + } + return result; + } + /** * The base implementation of `_.flatten` without support for callback * shorthands or `thisArg` binding. @@ -923,11 +1069,11 @@ var global=self;/** * @private * @param {Array} array The array to flatten. * @param {boolean} [isShallow=false] A flag to restrict flattening to a single level. - * @param {boolean} [isArgArrays=false] A flag to restrict flattening to arrays and `arguments` objects. + * @param {boolean} [isStrict=false] A flag to restrict flattening to arrays and `arguments` objects. * @param {number} [fromIndex=0] The index to start from. * @returns {Array} Returns a new flattened array. */ - function baseFlatten(array, isShallow, isArgArrays, fromIndex) { + function baseFlatten(array, isShallow, isStrict, fromIndex) { var index = (fromIndex || 0) - 1, length = array ? array.length : 0, result = []; @@ -939,7 +1085,7 @@ var global=self;/** && (isArray(value) || isArguments(value))) { // recursively flatten arrays (susceptible to call stack limits) if (!isShallow) { - value = baseFlatten(value, isShallow, isArgArrays); + value = baseFlatten(value, isShallow, isStrict); } var valIndex = -1, valLength = value.length, @@ -949,7 +1095,7 @@ var global=self;/** while (++valIndex < valLength) { result[resIndex++] = value[valIndex]; } - } else if (!isArgArrays) { + } else if (!isStrict) { result.push(value); } } @@ -1032,8 +1178,11 @@ var global=self;/** var isArr = className == arrayClass; if (!isArr) { // unwrap any `lodash` wrapped values - if (hasOwnProperty.call(a, '__wrapped__ ') || hasOwnProperty.call(b, '__wrapped__')) { - return baseIsEqual(a.__wrapped__ || a, b.__wrapped__ || b, callback, isWhere, stackA, stackB); + var aWrapped = hasOwnProperty.call(a, '__wrapped__'), + bWrapped = hasOwnProperty.call(b, '__wrapped__'); + + if (aWrapped || bWrapped) { + return baseIsEqual(aWrapped ? a.__wrapped__ : a, bWrapped ? b.__wrapped__ : b, callback, isWhere, stackA, stackB); } // exit for functions and DOM nodes if (className != objectClass) { @@ -1044,10 +1193,10 @@ var global=self;/** 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 - )) { + if (ctorA != ctorB && + !(isFunction(ctorA) && ctorA instanceof ctorA && isFunction(ctorB) && ctorB instanceof ctorB) && + ('constructor' in a && 'constructor' in b) + ) { return false; } } @@ -1073,51 +1222,54 @@ var global=self;/** // recursively compare objects and arrays (susceptible to call stack limits) if (isArr) { + // compare lengths to determine if a deep comparison is necessary length = a.length; size = b.length; + result = size == length; - // compare lengths to determine if a deep comparison is necessary - result = size == a.length; - if (!result && !isWhere) { - return result; - } - // deep compare the contents, ignoring non-numeric properties - while (size--) { - var index = length, - value = b[size]; + if (result || isWhere) { + // deep compare the contents, ignoring non-numeric properties + while (size--) { + var index = length, + value = b[size]; - if (isWhere) { - while (index--) { - if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) { - break; + if (isWhere) { + while (index--) { + if ((result = baseIsEqual(a[index], value, callback, isWhere, stackA, stackB))) { + break; + } } + } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, stackA, stackB))) { + break; } - } else if (!(result = baseIsEqual(a[size], value, callback, isWhere, 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(b, function(value, key, b) { - if (hasOwnProperty.call(b, key)) { - // count the number of properties. - size++; - // deep compare each property value. - return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB)); - } - }); - - if (result && !isWhere) { - // ensure both objects have the same number of properties - forIn(a, function(value, key, a) { - if (hasOwnProperty.call(a, key)) { - // `size` will be `-1` if `a` has more properties than `b` - return (result = --size > -1); + else { + // deep compare objects using `forIn`, instead of `forOwn`, to avoid `Object.keys` + // which, in this case, is more costly + forIn(b, function(value, key, b) { + if (hasOwnProperty.call(b, key)) { + // count the number of properties. + size++; + // deep compare each property value. + return (result = hasOwnProperty.call(a, key) && baseIsEqual(a[key], value, callback, isWhere, stackA, stackB)); } }); + + if (result && !isWhere) { + // ensure both objects have the same number of properties + forIn(a, function(value, key, a) { + if (hasOwnProperty.call(a, key)) { + // `size` will be `-1` if `a` has more properties than `b` + return (result = --size > -1); + } + }); + } } + stackA.pop(); + stackB.pop(); + if (initedStack) { releaseArray(stackA); releaseArray(stackB); @@ -1190,6 +1342,19 @@ var global=self;/** }); } + /** + * The base implementation of `_.random` without argument juggling or support + * for returning floating-point numbers. + * + * @private + * @param {number} min The minimum possible value. + * @param {number} max The maximum possible value. + * @returns {number} Returns a random number. + */ + function baseRandom(min, max) { + return min + floor(nativeRandom() * (max - min + 1)); + } + /** * The base implementation of `_.uniq` without support for callback shorthands * or `thisArg` binding. @@ -1211,13 +1376,8 @@ var global=self;/** if (isLarge) { var cache = createCache(seen); - if (cache) { - indexOf = cacheIndexOf; - seen = cache; - } else { - isLarge = false; - seen = callback ? seen : (releaseArray(seen), result); - } + indexOf = cacheIndexOf; + seen = cache; } while (++index < length) { var value = array[index], @@ -1294,16 +1454,15 @@ var global=self;/** * provided to the new function. * @param {*} [thisArg] The `this` binding of `func`. * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new bound function. + * @returns {Function} Returns the new function. */ - function createBound(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) { + function createWrapper(func, bitmask, partialArgs, partialRightArgs, thisArg, arity) { var isBind = bitmask & 1, isBindKey = bitmask & 2, isCurry = bitmask & 4, isCurryBound = bitmask & 8, isPartial = bitmask & 16, - isPartialRight = bitmask & 32, - key = func; + isPartialRight = bitmask & 32; if (!isBindKey && !isFunction(func)) { throw new TypeError; @@ -1317,96 +1476,42 @@ var global=self;/** isPartialRight = partialRightArgs = false; } var bindData = func && func.__bindData__; - if (bindData) { + if (bindData && bindData !== true) { + // clone `bindData` + bindData = slice(bindData); + if (bindData[2]) { + bindData[2] = slice(bindData[2]); + } + if (bindData[3]) { + bindData[3] = slice(bindData[3]); + } + // set `thisBinding` is not previously bound if (isBind && !(bindData[1] & 1)) { bindData[4] = thisArg; } + // set if previously bound but not currently (subsequent curried functions) if (!isBind && bindData[1] & 1) { bitmask |= 8; } + // set curried arity if not yet set if (isCurry && !(bindData[1] & 4)) { bindData[5] = arity; } + // append partial left arguments if (isPartial) { push.apply(bindData[2] || (bindData[2] = []), partialArgs); } + // append partial right arguments if (isPartialRight) { - push.apply(bindData[3] || (bindData[3] = []), partialRightArgs); + unshift.apply(bindData[3] || (bindData[3] = []), partialRightArgs); } + // merge flags bindData[1] |= bitmask; - return createBound.apply(null, bindData); + return createWrapper.apply(null, bindData); } - // use `Function#bind` if it exists and is fast - // (in V8 `Function#bind` is slower except when partially applied) - if (isBind && !(isBindKey || isCurry || isPartialRight) && - (support.fastBind || (nativeBind && isPartial))) { - if (isPartial) { - var args = [thisArg]; - push.apply(args, partialArgs); - } - var bound = isPartial - ? nativeBind.apply(func, args) - : nativeBind.call(func, thisArg); - } - else { - bound = function() { - // `Function#bind` spec - // http://es5.github.io/#x15.3.4.5 - var args = arguments, - thisBinding = isBind ? thisArg : this; - - if (isCurry || isPartial || isPartialRight) { - args = nativeSlice.call(args); - if (isPartial) { - unshift.apply(args, partialArgs); - } - if (isPartialRight) { - push.apply(args, partialRightArgs); - } - if (isCurry && args.length < arity) { - bitmask |= 16 & ~32; - return createBound(func, (isCurryBound ? bitmask : bitmask & ~3), args, null, thisArg, arity); - } - } - if (isBindKey) { - func = thisBinding[key]; - } - if (this instanceof bound) { - // ensure `new bound` is an instance of `func` - thisBinding = createObject(func.prototype); - - // mimic the constructor's `return` behavior - // http://es5.github.io/#x13.2.2 - var result = func.apply(thisBinding, args); - return isObject(result) ? result : thisBinding; - } - return func.apply(thisBinding, args); - }; - } - setBindData(bound, nativeSlice.call(arguments)); - return bound; - } - - /** - * Creates a new object with the specified `prototype`. - * - * @private - * @param {Object} prototype The prototype object. - * @returns {Object} Returns the new object. - */ - function createObject(prototype) { - return isObject(prototype) ? nativeCreate(prototype) : {}; - } - // fallback for browsers without `Object.create` - if (!nativeCreate) { - createObject = function(prototype) { - if (isObject(prototype)) { - noop.prototype = prototype; - var result = new noop; - noop.prototype = null; - } - return result || {}; - }; + // fast path for `_.bind` + var creater = (bitmask == 1 || bitmask === 17) ? baseBind : baseCreateWrapper; + return creater([func, bitmask, partialArgs, partialRightArgs, thisArg, arity]); } /** @@ -1433,12 +1538,23 @@ var global=self;/** return result; } + /** + * Checks if `value` is a native function. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if the `value` is a native function, else `false`. + */ + function isNative(value) { + return typeof value == 'function' && reNative.test(value); + } + /** * Sets `this` binding data on a given function. * * @private * @param {Function} func The function to set data on. - * @param {*} value The value to set. + * @param {Array} value The data array to set. */ var setBindData = !defineProperty ? noop : function(func, value) { descriptor.value = value; @@ -1614,16 +1730,16 @@ var global=self;/** * @returns {Object} Returns the destination object. * @example * - * _.assign({ 'name': 'moe' }, { 'age': 40 }); - * // => { 'name': 'moe', 'age': 40 } + * _.assign({ 'name': 'fred' }, { 'employer': 'slate' }); + * // => { 'name': 'fred', 'employer': 'slate' } * * var defaults = _.partialRight(_.assign, function(a, b) { * return typeof a == 'undefined' ? b : a; * }); * - * var food = { 'name': 'apple' }; - * defaults(food, { 'name': 'banana', 'type': 'fruit' }); - * // => { 'name': 'apple', 'type': 'fruit' } + * var object = { 'name': 'barney' }; + * defaults(object, { 'name': 'fred', 'employer': 'slate' }); + * // => { 'name': 'barney', 'employer': 'slate' } */ var assign = function(object, source, guard) { var index, iterable = object, result = iterable; @@ -1653,7 +1769,7 @@ var global=self;/** }; /** - * Creates a clone of `value`. If `deep` is `true` nested objects will also + * Creates a clone of `value`. If `isDeep` is `true` nested objects will also * be cloned, otherwise they will be assigned by reference. If a callback * is provided it will be executed to produce the cloned values. If the * callback returns `undefined` cloning will be handled by the method instead. @@ -1663,23 +1779,23 @@ var global=self;/** * @memberOf _ * @category Objects * @param {*} value The value to clone. - * @param {boolean} [deep=false] Specify a deep clone. + * @param {boolean} [isDeep=false] Specify a deep clone. * @param {Function} [callback] The function to customize cloning values. * @param {*} [thisArg] The `this` binding of `callback`. * @returns {*} Returns the cloned value. * @example * - * var stooges = [ - * { 'name': 'moe', 'age': 40 }, - * { 'name': 'larry', 'age': 50 } + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } * ]; * - * var shallow = _.clone(stooges); - * shallow[0] === stooges[0]; + * var shallow = _.clone(characters); + * shallow[0] === characters[0]; * // => true * - * var deep = _.clone(stooges, true); - * deep[0] === stooges[0]; + * var deep = _.clone(characters, true); + * deep[0] === characters[0]; * // => false * * _.mixin({ @@ -1692,15 +1808,15 @@ var global=self;/** * clone.childNodes.length; * // => 0 */ - function clone(value, deep, callback, thisArg) { + function clone(value, isDeep, callback, thisArg) { // allows working with "Collections" methods without using their `index` - // and `collection` arguments for `deep` and `callback` - if (typeof deep != 'boolean' && deep != null) { + // and `collection` arguments for `isDeep` and `callback` + if (typeof isDeep != 'boolean' && isDeep != null) { thisArg = callback; - callback = deep; - deep = false; + callback = isDeep; + isDeep = false; } - return baseClone(value, deep, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1)); + return baseClone(value, isDeep, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1)); } /** @@ -1723,13 +1839,13 @@ var global=self;/** * @returns {*} Returns the deep cloned value. * @example * - * var stooges = [ - * { 'name': 'moe', 'age': 40 }, - * { 'name': 'larry', 'age': 50 } + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } * ]; * - * var deep = _.cloneDeep(stooges); - * deep[0] === stooges[0]; + * var deep = _.cloneDeep(characters); + * deep[0] === characters[0]; * // => false * * var view = { @@ -1748,6 +1864,42 @@ var global=self;/** return baseClone(value, true, typeof callback == 'function' && baseCreateCallback(callback, thisArg, 1)); } + /** + * Creates an object that inherits from the given `prototype` object. If a + * `properties` object is provided its own enumerable properties are assigned + * to the created object. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} prototype The object to inherit from. + * @param {Object} [properties] The properties to assign to the object. + * @returns {Object} Returns the new object. + * @example + * + * function Shape() { + * this.x = 0; + * this.y = 0; + * } + * + * function Circle() { + * Shape.call(this); + * } + * + * Circle.prototype = _.create(Shape.prototype, { 'constructor': Circle }); + * + * var circle = new Circle; + * circle instanceof Circle; + * // => true + * + * circle instanceof Shape; + * // => true + */ + function create(prototype, properties) { + var result = baseCreate(prototype); + return properties ? assign(result, properties) : result; + } + /** * Assigns own enumerable properties of source object(s) to the destination * object for all destination properties that resolve to `undefined`. Once a @@ -1764,9 +1916,9 @@ var global=self;/** * @returns {Object} Returns the destination object. * @example * - * var food = { 'name': 'apple' }; - * _.defaults(food, { 'name': 'banana', 'type': 'fruit' }); - * // => { 'name': 'apple', 'type': 'fruit' } + * var object = { 'name': 'barney' }; + * _.defaults(object, { 'name': 'fred', 'employer': 'slate' }); + * // => { 'name': 'barney', 'employer': 'slate' } */ var defaults = function(object, source, guard) { var index, iterable = object, result = iterable; @@ -1794,6 +1946,13 @@ var global=self;/** * This method is like `_.findIndex` except that it returns the key of the * first element that passes the callback check, instead of the element itself. * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * * @static * @memberOf _ * @category Objects @@ -1805,10 +1964,24 @@ var global=self;/** * @returns {string|undefined} Returns the key of the found element, else `undefined`. * @example * - * _.findKey({ 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, function(num) { - * return num % 2 == 0; + * var characters = { + * 'barney': { 'age': 36, 'blocked': false }, + * 'fred': { 'age': 40, 'blocked': true }, + * 'pebbles': { 'age': 1, 'blocked': false } + * }; + * + * _.findKey(characters, function(chr) { + * return chr.age < 40; * }); - * // => 'b' (property order is not guaranteed across environments) + * // => 'barney' (property order is not guaranteed across environments) + * + * // using "_.where" callback shorthand + * _.findKey(characters, { 'age': 1 }); + * // => 'pebbles' + * + * // using "_.pluck" callback shorthand + * _.findKey(characters, 'blocked'); + * // => 'fred' */ function findKey(object, callback, thisArg) { var result; @@ -1826,6 +1999,13 @@ var global=self;/** * This method is like `_.findKey` except that it iterates over elements * of a `collection` in the opposite order. * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * * @static * @memberOf _ * @category Objects @@ -1837,10 +2017,24 @@ var global=self;/** * @returns {string|undefined} Returns the key of the found element, else `undefined`. * @example * - * _.findLastKey({ 'a': 1, 'b': 2, 'c': 3, 'd': 4 }, function(num) { - * return num % 2 == 1; + * var characters = { + * 'barney': { 'age': 36, 'blocked': true }, + * 'fred': { 'age': 40, 'blocked': false }, + * 'pebbles': { 'age': 1, 'blocked': true } + * }; + * + * _.findLastKey(characters, function(chr) { + * return chr.age < 40; * }); - * // => returns `c`, assuming `_.findKey` returns `a` + * // => returns `pebbles`, assuming `_.findKey` returns `barney` + * + * // using "_.where" callback shorthand + * _.findLastKey(characters, { 'age': 40 }); + * // => 'fred' + * + * // using "_.pluck" callback shorthand + * _.findLastKey(characters, 'blocked'); + * // => 'pebbles' */ function findLastKey(object, callback, thisArg) { var result; @@ -1870,18 +2064,20 @@ var global=self;/** * @returns {Object} Returns `object`. * @example * - * function Dog(name) { - * this.name = name; + * function Shape() { + * this.x = 0; + * this.y = 0; * } * - * Dog.prototype.bark = function() { - * console.log('Woof, woof!'); + * Shape.prototype.move = function(x, y) { + * this.x += x; + * this.y += y; * }; * - * _.forIn(new Dog('Dagny'), function(value, key) { + * _.forIn(new Shape, function(value, key) { * console.log(key); * }); - * // => logs 'bark' and 'name' (property order is not guaranteed across environments) + * // => logs 'x', 'y', and 'move' (property order is not guaranteed across environments) */ var forIn = function(collection, callback, thisArg) { var index, iterable = collection, result = iterable; @@ -1907,18 +2103,20 @@ var global=self;/** * @returns {Object} Returns `object`. * @example * - * function Dog(name) { - * this.name = name; + * function Shape() { + * this.x = 0; + * this.y = 0; * } * - * Dog.prototype.bark = function() { - * console.log('Woof, woof!'); + * Shape.prototype.move = function(x, y) { + * this.x += x; + * this.y += y; * }; * - * _.forInRight(new Dog('Dagny'), function(value, key) { + * _.forInRight(new Shape, function(value, key) { * console.log(key); * }); - * // => logs 'name' and 'bark' assuming `_.forIn ` logs 'bark' and 'name' + * // => logs 'move', 'y', and 'x' assuming `_.forIn ` logs 'x', 'y', and 'move' */ function forInRight(object, callback, thisArg) { var pairs = []; @@ -2032,22 +2230,22 @@ var global=self;/** } /** - * Checks if the specified object `property` exists and is a direct property, + * Checks if the specified property name exists as a direct property of `object`, * instead of an inherited property. * * @static * @memberOf _ * @category Objects - * @param {Object} object The object to check. - * @param {string} property The property to check for. + * @param {Object} object The object to inspect. + * @param {string} key The name of the property to check. * @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; + function has(object, key) { + return object ? hasOwnProperty.call(object, key) : false; } /** @@ -2060,8 +2258,8 @@ var global=self;/** * @returns {Object} Returns the created inverted object. * @example * - * _.invert({ 'first': 'moe', 'second': 'larry' }); - * // => { 'moe': 'first', 'larry': 'second' } + * _.invert({ 'first': 'fred', 'second': 'barney' }); + * // => { 'fred': 'first', 'barney': 'second' } */ function invert(object) { var index = -1, @@ -2090,7 +2288,8 @@ var global=self;/** * // => false */ function isBoolean(value) { - return value === true || value === false || toString.call(value) == boolClass; + return value === true || value === false || + value && typeof value == 'object' && toString.call(value) == boolClass || false; } /** @@ -2107,7 +2306,7 @@ var global=self;/** * // => true */ function isDate(value) { - return value ? (typeof value == 'object' && toString.call(value) == dateClass) : false; + return value && typeof value == 'object' && toString.call(value) == dateClass || false; } /** @@ -2124,7 +2323,7 @@ var global=self;/** * // => true */ function isElement(value) { - return value ? value.nodeType === 1 : false; + return value && value.nodeType === 1 || false; } /** @@ -2183,13 +2382,13 @@ var global=self;/** * @returns {boolean} Returns `true` if the values are equivalent, else `false`. * @example * - * var moe = { 'name': 'moe', 'age': 40 }; - * var copy = { 'name': 'moe', 'age': 40 }; + * var object = { 'name': 'fred' }; + * var copy = { 'name': 'fred' }; * - * moe == copy; + * object == copy; * // => false * - * _.isEqual(moe, copy); + * _.isEqual(object, copy); * // => true * * var words = ['hello', 'goodbye']; @@ -2352,7 +2551,8 @@ var global=self;/** * // => true */ function isNumber(value) { - return typeof value == 'number' || toString.call(value) == numberClass; + return typeof value == 'number' || + value && typeof value == 'object' && toString.call(value) == numberClass || false; } /** @@ -2365,26 +2565,26 @@ var global=self;/** * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. * @example * - * function Stooge(name, age) { - * this.name = name; - * this.age = age; + * function Shape() { + * this.x = 0; + * this.y = 0; * } * - * _.isPlainObject(new Stooge('moe', 40)); + * _.isPlainObject(new Shape); * // => false * * _.isPlainObject([1, 2, 3]); * // => false * - * _.isPlainObject({ 'name': 'moe', 'age': 40 }); + * _.isPlainObject({ 'x': 0, 'y': 0 }); * // => true */ - var isPlainObject = function(value) { + var isPlainObject = !getPrototypeOf ? shimIsPlainObject : function(value) { if (!(value && toString.call(value) == objectClass)) { return false; } var valueOf = value.valueOf, - objProto = typeof valueOf == 'function' && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto); + objProto = isNative(valueOf) && (objProto = getPrototypeOf(valueOf)) && getPrototypeOf(objProto); return objProto ? (value == objProto || getPrototypeOf(value) == objProto) @@ -2401,11 +2601,11 @@ var global=self;/** * @returns {boolean} Returns `true` if the `value` is a regular expression, else `false`. * @example * - * _.isRegExp(/moe/); + * _.isRegExp(/fred/); * // => true */ function isRegExp(value) { - return value ? (typeof value == 'object' && toString.call(value) == regexpClass) : false; + return value && typeof value == 'object' && toString.call(value) == regexpClass || false; } /** @@ -2418,11 +2618,12 @@ var global=self;/** * @returns {boolean} Returns `true` if the `value` is a string, else `false`. * @example * - * _.isString('moe'); + * _.isString('fred'); * // => true */ function isString(value) { - return typeof value == 'string' || toString.call(value) == stringClass; + return typeof value == 'string' || + value && typeof value == 'object' && toString.call(value) == stringClass || false; } /** @@ -2442,6 +2643,52 @@ var global=self;/** return typeof value == 'undefined'; } + /** + * Creates an object with the same keys as `object` and values generated by + * running each own enumerable property of `object` through the callback. + * The callback is bound to `thisArg` and invoked with three arguments; + * (value, key, object). + * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * + * @static + * @memberOf _ + * @category Objects + * @param {Object} object The object to iterate over. + * @param {Function|Object|string} [callback=identity] The function called + * per iteration. If a property name or object is provided it will be used + * to create a "_.pluck" or "_.where" style callback, respectively. + * @param {*} [thisArg] The `this` binding of `callback`. + * @returns {Array} Returns a new object with values of the results of each `callback` execution. + * @example + * + * _.mapValues({ 'a': 1, 'b': 2, 'c': 3} , function(num) { return num * 3; }); + * // => { 'a': 3, 'b': 6, 'c': 9 } + * + * var characters = { + * 'fred': { 'name': 'fred', 'age': 40 }, + * 'pebbles': { 'name': 'pebbles', 'age': 1 } + * }; + * + * // using "_.pluck" callback shorthand + * _.mapValues(characters, 'age'); + * // => { 'fred': 40, 'pebbles': 1 } + */ + function mapValues(object, callback, thisArg) { + var result = {}; + callback = lodash.createCallback(callback, thisArg, 3); + + forOwn(object, function(value, key, object) { + result[key] = callback(value, key, object); + }); + return result; + } + /** * Recursively merges own enumerable properties of the source object(s), that * don't resolve to `undefined` into the destination object. Subsequent sources @@ -2462,21 +2709,21 @@ var global=self;/** * @example * * var names = { - * 'stooges': [ - * { 'name': 'moe' }, - * { 'name': 'larry' } + * 'characters': [ + * { 'name': 'barney' }, + * { 'name': 'fred' } * ] * }; * * var ages = { - * 'stooges': [ - * { 'age': 40 }, - * { 'age': 50 } + * 'characters': [ + * { 'age': 36 }, + * { 'age': 40 } * ] * }; * * _.merge(names, ages); - * // => { 'stooges': [{ 'name': 'moe', 'age': 40 }, { 'name': 'larry', 'age': 50 }] } + * // => { 'characters': [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] } * * var food = { * 'fruits': ['apple'], @@ -2510,7 +2757,7 @@ var global=self;/** } else if (length > 2 && typeof args[length - 1] == 'function') { callback = args[--length]; } - var sources = nativeSlice.call(arguments, 1, length), + var sources = slice(arguments, 1, length), index = -1, stackA = getArray(), stackB = getArray(); @@ -2541,32 +2788,38 @@ var global=self;/** * @returns {Object} Returns an object without the omitted properties. * @example * - * _.omit({ 'name': 'moe', 'age': 40 }, 'age'); - * // => { 'name': 'moe' } + * _.omit({ 'name': 'fred', 'age': 40 }, 'age'); + * // => { 'name': 'fred' } * - * _.omit({ 'name': 'moe', 'age': 40 }, function(value) { + * _.omit({ 'name': 'fred', 'age': 40 }, function(value) { * return typeof value == 'number'; * }); - * // => { 'name': 'moe' } + * // => { 'name': 'fred' } */ function omit(object, callback, thisArg) { - var indexOf = getIndexOf(), - isFunc = typeof callback == 'function', - result = {}; + var result = {}; + if (typeof callback != 'function') { + var props = []; + forIn(object, function(value, key) { + props.push(key); + }); + props = baseDifference(props, baseFlatten(arguments, true, false, 1)); - if (isFunc) { - callback = lodash.createCallback(callback, thisArg, 3); - } else { - var props = baseFlatten(arguments, true, false, 1); - } - forIn(object, function(value, key, object) { - if (isFunc - ? !callback(value, key, object) - : indexOf(props, key) < 0 - ) { - result[key] = value; + var index = -1, + length = props.length; + + while (++index < length) { + var key = props[index]; + result[key] = object[key]; } - }); + } else { + callback = lodash.createCallback(callback, thisArg, 3); + forIn(object, function(value, key, object) { + if (!callback(value, key, object)) { + result[key] = value; + } + }); + } return result; } @@ -2581,8 +2834,8 @@ var global=self;/** * @returns {Array} Returns new array of key-value pairs. * @example * - * _.pairs({ 'moe': 30, 'larry': 40 }); - * // => [['moe', 30], ['larry', 40]] (property order is not guaranteed across environments) + * _.pairs({ 'barney': 36, 'fred': 40 }); + * // => [['barney', 36], ['fred', 40]] (property order is not guaranteed across environments) */ function pairs(object) { var index = -1, @@ -2616,13 +2869,13 @@ var global=self;/** * @returns {Object} Returns an object composed of the picked properties. * @example * - * _.pick({ 'name': 'moe', '_userid': 'moe1' }, 'name'); - * // => { 'name': 'moe' } + * _.pick({ 'name': 'fred', '_userid': 'fred1' }, 'name'); + * // => { 'name': 'fred' } * - * _.pick({ 'name': 'moe', '_userid': 'moe1' }, function(value, key) { + * _.pick({ 'name': 'fred', '_userid': 'fred1' }, function(value, key) { * return key.charAt(0) != '_'; * }); - * // => { 'name': 'moe' } + * // => { 'name': 'fred' } */ function pick(object, callback, thisArg) { var result = {}; @@ -2650,16 +2903,16 @@ var global=self;/** /** * An alternative to `_.reduce` this method transforms `object` to a new - * `accumulator` object which is the result of running each of its elements - * through a callback, with each callback execution potentially mutating - * the `accumulator` object. The callback is bound to `thisArg` and invoked - * with four arguments; (accumulator, value, key, object). Callbacks may exit - * iteration early by explicitly returning `false`. + * `accumulator` object which is the result of running each of its own + * enumerable properties through a callback, with each callback execution + * potentially mutating the `accumulator` object. The callback is bound to + * `thisArg` and invoked with four arguments; (accumulator, value, key, object). + * Callbacks may exit iteration early by explicitly returning `false`. * * @static * @memberOf _ * @category Objects - * @param {Array|Object} collection The collection to iterate over. + * @param {Array|Object} object The object to iterate over. * @param {Function} [callback=identity] The function called per iteration. * @param {*} [accumulator] The custom accumulator value. * @param {*} [thisArg] The `this` binding of `callback`. @@ -2681,8 +2934,6 @@ var global=self;/** */ function transform(object, callback, accumulator, thisArg) { var isArr = isArray(object); - callback = baseCreateCallback(callback, thisArg, 4); - if (accumulator == null) { if (isArr) { accumulator = []; @@ -2690,12 +2941,15 @@ var global=self;/** var ctor = object && object.constructor, proto = ctor && ctor.prototype; - accumulator = createObject(proto); + accumulator = baseCreate(proto); } } - (isArr ? forEach : forOwn)(object, function(value, index, object) { - return callback(accumulator, value, index, object); - }); + if (callback) { + callback = lodash.createCallback(callback, thisArg, 4); + (isArr ? forEach : forOwn)(object, function(value, index, object) { + return callback(accumulator, value, index, object); + }); + } return accumulator; } @@ -2744,8 +2998,8 @@ var global=self;/** * _.at(['a', 'b', 'c', 'd', 'e'], [0, 2, 4]); * // => ['a', 'c', 'e'] * - * _.at(['moe', 'larry', 'curly'], 0, 2); - * // => ['moe', 'curly'] + * _.at(['fred', 'barney', 'pebbles'], 0, 2); + * // => ['fred', 'pebbles'] */ function at(collection) { var args = arguments, @@ -2781,10 +3035,10 @@ var global=self;/** * _.contains([1, 2, 3], 1, 2); * // => false * - * _.contains({ 'name': 'moe', 'age': 40 }, 'moe'); + * _.contains({ 'name': 'fred', 'age': 40 }, 'fred'); * // => true * - * _.contains('curly', 'ur'); + * _.contains('pebbles', 'eb'); * // => true */ function contains(collection, target, fromIndex) { @@ -2871,20 +3125,20 @@ var global=self;/** * else `false`. * @example * - * _.every([true, 1, null, 'yes'], Boolean); + * _.every([true, 1, null, 'yes']); * // => false * - * var stooges = [ - * { 'name': 'moe', 'age': 40 }, - * { 'name': 'larry', 'age': 50 } + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } * ]; * * // using "_.pluck" callback shorthand - * _.every(stooges, 'age'); + * _.every(characters, 'age'); * // => true * * // using "_.where" callback shorthand - * _.every(stooges, { 'age': 50 }); + * _.every(characters, { 'age': 36 }); * // => false */ function every(collection, callback, thisArg) { @@ -2935,18 +3189,18 @@ var global=self;/** * var evens = _.filter([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); * // => [2, 4, 6] * - * var food = [ - * { 'name': 'apple', 'organic': false, 'type': 'fruit' }, - * { 'name': 'carrot', 'organic': true, 'type': 'vegetable' } + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': false }, + * { 'name': 'fred', 'age': 40, 'blocked': true } * ]; * * // using "_.pluck" callback shorthand - * _.filter(food, 'organic'); - * // => [{ 'name': 'carrot', 'organic': true, 'type': 'vegetable' }] + * _.filter(characters, 'blocked'); + * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }] * * // using "_.where" callback shorthand - * _.filter(food, { 'type': 'fruit' }); - * // => [{ 'name': 'apple', 'organic': false, 'type': 'fruit' }] + * _.filter(characters, { 'age': 36 }); + * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }] */ function filter(collection, callback, thisArg) { var result = []; @@ -2996,24 +3250,24 @@ var global=self;/** * @returns {*} Returns the found element, else `undefined`. * @example * - * _.find([1, 2, 3, 4], function(num) { - * return num % 2 == 0; - * }); - * // => 2 - * - * var food = [ - * { 'name': 'apple', 'organic': false, 'type': 'fruit' }, - * { 'name': 'banana', 'organic': true, 'type': 'fruit' }, - * { 'name': 'beet', 'organic': false, 'type': 'vegetable' } + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': false }, + * { 'name': 'fred', 'age': 40, 'blocked': true }, + * { 'name': 'pebbles', 'age': 1, 'blocked': false } * ]; * + * _.find(characters, function(chr) { + * return chr.age < 40; + * }); + * // => { 'name': 'barney', 'age': 36, 'blocked': false } + * * // using "_.where" callback shorthand - * _.find(food, { 'type': 'vegetable' }); - * // => { 'name': 'beet', 'organic': false, 'type': 'vegetable' } + * _.find(characters, { 'age': 1 }); + * // => { 'name': 'pebbles', 'age': 1, 'blocked': false } * * // using "_.pluck" callback shorthand - * _.find(food, 'organic'); - * // => { 'name': 'banana', 'organic': true, 'type': 'fruit' } + * _.find(characters, 'blocked'); + * // => { 'name': 'fred', 'age': 40, 'blocked': true } */ function find(collection, callback, thisArg) { callback = lodash.createCallback(callback, thisArg, 3); @@ -3078,6 +3332,10 @@ var global=self;/** * (value, index|key, collection). Callbacks may exit iteration early by * explicitly returning `false`. * + * Note: As with other "Collections" methods, objects with a `length` property + * are iterated like arrays. To avoid this behavior `_.forIn` or `_.forOwn` + * may be used for object iteration. + * * @static * @memberOf _ * @alias each @@ -3223,7 +3481,7 @@ var global=self;/** * _.indexBy(keys, function(key) { return String.fromCharCode(key.code); }); * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } * - * _.indexBy(stooges, function(key) { this.fromCharCode(key.code); }, String); + * _.indexBy(characters, function(key) { this.fromCharCode(key.code); }, String); * // => { 'a': { 'dir': 'left', 'code': 97 }, 'd': { 'dir': 'right', 'code': 100 } } */ var indexBy = createAggregator(function(result, value, key) { @@ -3253,7 +3511,7 @@ var global=self;/** * // => [['1', '2', '3'], ['4', '5', '6']] */ function invoke(collection, methodName) { - var args = nativeSlice.call(arguments, 2), + var args = slice(arguments, 2), index = -1, isFunc = typeof methodName == 'function', length = collection ? collection.length : 0, @@ -3295,14 +3553,14 @@ var global=self;/** * _.map({ 'one': 1, 'two': 2, 'three': 3 }, function(num) { return num * 3; }); * // => [3, 6, 9] (property order is not guaranteed across environments) * - * var stooges = [ - * { 'name': 'moe', 'age': 40 }, - * { 'name': 'larry', 'age': 50 } + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } * ]; * * // using "_.pluck" callback shorthand - * _.map(stooges, 'name'); - * // => ['moe', 'larry'] + * _.map(characters, 'name'); + * // => ['barney', 'fred'] */ function map(collection, callback, thisArg) { var index = -1, @@ -3351,23 +3609,28 @@ var global=self;/** * _.max([4, 2, 8, 6]); * // => 8 * - * var stooges = [ - * { 'name': 'moe', 'age': 40 }, - * { 'name': 'larry', 'age': 50 } + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } * ]; * - * _.max(stooges, function(stooge) { return stooge.age; }); - * // => { 'name': 'larry', 'age': 50 }; + * _.max(characters, function(chr) { return chr.age; }); + * // => { 'name': 'fred', 'age': 40 }; * * // using "_.pluck" callback shorthand - * _.max(stooges, 'age'); - * // => { 'name': 'larry', 'age': 50 }; + * _.max(characters, 'age'); + * // => { 'name': 'fred', 'age': 40 }; */ function max(collection, callback, thisArg) { var computed = -Infinity, result = computed; - if (!callback && isArray(collection)) { + // allows working with functions like `_.map` without using + // their `index` argument as a callback + if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) { + callback = null; + } + if (callback == null && isArray(collection)) { var index = -1, length = collection.length; @@ -3378,7 +3641,7 @@ var global=self;/** } } } else { - callback = (!callback && isString(collection)) + callback = (callback == null && isString(collection)) ? charAtCallback : lodash.createCallback(callback, thisArg, 3); @@ -3421,23 +3684,28 @@ var global=self;/** * _.min([4, 2, 8, 6]); * // => 2 * - * var stooges = [ - * { 'name': 'moe', 'age': 40 }, - * { 'name': 'larry', 'age': 50 } + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } * ]; * - * _.min(stooges, function(stooge) { return stooge.age; }); - * // => { 'name': 'moe', 'age': 40 }; + * _.min(characters, function(chr) { return chr.age; }); + * // => { 'name': 'barney', 'age': 36 }; * * // using "_.pluck" callback shorthand - * _.min(stooges, 'age'); - * // => { 'name': 'moe', 'age': 40 }; + * _.min(characters, 'age'); + * // => { 'name': 'barney', 'age': 36 }; */ function min(collection, callback, thisArg) { var computed = Infinity, result = computed; - if (!callback && isArray(collection)) { + // allows working with functions like `_.map` without using + // their `index` argument as a callback + if (typeof callback != 'function' && thisArg && thisArg[callback] === collection) { + callback = null; + } + if (callback == null && isArray(collection)) { var index = -1, length = collection.length; @@ -3448,7 +3716,7 @@ var global=self;/** } } } else { - callback = (!callback && isString(collection)) + callback = (callback == null && isString(collection)) ? charAtCallback : lodash.createCallback(callback, thisArg, 3); @@ -3464,37 +3732,26 @@ var global=self;/** } /** - * Retrieves the value of a specified property from all elements in the `collection`. + * Retrieves the value of a specified property from all elements in the collection. * * @static * @memberOf _ * @type Function * @category Collections * @param {Array|Object|string} collection The collection to iterate over. - * @param {string} property The property to pluck. + * @param {string} property The name of the property to pluck. * @returns {Array} Returns a new array of property values. * @example * - * var stooges = [ - * { 'name': 'moe', 'age': 40 }, - * { 'name': 'larry', 'age': 50 } + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } * ]; * - * _.pluck(stooges, 'name'); - * // => ['moe', 'larry'] + * _.pluck(characters, 'name'); + * // => ['barney', 'fred'] */ - function pluck(collection, property) { - var index = -1, - length = collection ? collection.length : 0; - - if (typeof length == 'number') { - var result = Array(length); - while (++index < length) { - result[index] = collection[index][property]; - } - } - return result || map(collection, property); - } + var pluck = map; /** * Reduces a collection to a value which is the accumulated result of running @@ -3529,7 +3786,7 @@ var global=self;/** function reduce(collection, callback, accumulator, thisArg) { if (!collection) return accumulator; var noaccum = arguments.length < 3; - callback = baseCreateCallback(callback, thisArg, 4); + callback = lodash.createCallback(callback, thisArg, 4); var index = -1, length = collection.length; @@ -3572,7 +3829,7 @@ var global=self;/** */ function reduceRight(collection, callback, accumulator, thisArg) { var noaccum = arguments.length < 3; - callback = baseCreateCallback(callback, thisArg, 4); + callback = lodash.createCallback(callback, thisArg, 4); forEachRight(collection, function(value, index, collection) { accumulator = noaccum ? (noaccum = false, value) @@ -3606,18 +3863,18 @@ var global=self;/** * var odds = _.reject([1, 2, 3, 4, 5, 6], function(num) { return num % 2 == 0; }); * // => [1, 3, 5] * - * var food = [ - * { 'name': 'apple', 'organic': false, 'type': 'fruit' }, - * { 'name': 'carrot', 'organic': true, 'type': 'vegetable' } + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': false }, + * { 'name': 'fred', 'age': 40, 'blocked': true } * ]; * * // using "_.pluck" callback shorthand - * _.reject(food, 'organic'); - * // => [{ 'name': 'apple', 'organic': false, 'type': 'fruit' }] + * _.reject(characters, 'blocked'); + * // => [{ 'name': 'barney', 'age': 36, 'blocked': false }] * * // using "_.where" callback shorthand - * _.reject(food, { 'type': 'fruit' }); - * // => [{ 'name': 'carrot', 'organic': true, 'type': 'vegetable' }] + * _.reject(characters, { 'age': 36 }); + * // => [{ 'name': 'fred', 'age': 40, 'blocked': true }] */ function reject(collection, callback, thisArg) { callback = lodash.createCallback(callback, thisArg, 3); @@ -3634,8 +3891,8 @@ var global=self;/** * @category Collections * @param {Array|Object|string} collection The collection to sample. * @param {number} [n] The number of elements to sample. - * @param- {Object} [guard] Allows working with functions, like `_.map`, - * without using their `key` and `object` arguments as sources. + * @param- {Object} [guard] Allows working with functions like `_.map` + * without using their `index` arguments as `n`. * @returns {Array} Returns the random sample(s) of `collection`. * @example * @@ -3646,12 +3903,11 @@ var global=self;/** * // => [3, 1] */ function sample(collection, n, guard) { - var length = collection ? collection.length : 0; - if (typeof length != 'number') { + if (collection && typeof collection.length != 'number') { collection = values(collection); } if (n == null || guard) { - return collection ? collection[random(length - 1)] : undefined; + return collection ? collection[baseRandom(0, collection.length - 1)] : undefined; } var result = shuffle(collection); result.length = nativeMin(nativeMax(0, n), result.length); @@ -3678,7 +3934,7 @@ var global=self;/** result = Array(typeof length == 'number' ? length : 0); forEach(collection, function(value) { - var rand = random(++index); + var rand = baseRandom(0, ++index); result[index] = result[rand]; result[rand] = value; }); @@ -3702,8 +3958,8 @@ var global=self;/** * _.size({ 'one': 1, 'two': 2, 'three': 3 }); * // => 3 * - * _.size('curly'); - * // => 5 + * _.size('pebbles'); + * // => 7 */ function size(collection) { var length = collection ? collection.length : 0; @@ -3739,17 +3995,17 @@ var global=self;/** * _.some([null, 0, 'yes', false], Boolean); * // => true * - * var food = [ - * { 'name': 'apple', 'organic': false, 'type': 'fruit' }, - * { 'name': 'carrot', 'organic': true, 'type': 'vegetable' } + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': false }, + * { 'name': 'fred', 'age': 40, 'blocked': true } * ]; * * // using "_.pluck" callback shorthand - * _.some(food, 'organic'); + * _.some(characters, 'blocked'); * // => true * * // using "_.where" callback shorthand - * _.some(food, { 'type': 'meat' }); + * _.some(characters, { 'age': 1 }); * // => false */ function some(collection, callback, thisArg) { @@ -3783,6 +4039,9 @@ var global=self;/** * If a property name is provided for `callback` the created "_.pluck" style * callback will return the property value of the given element. * + * If an array of property names is provided for `callback` the collection + * will be sorted by each property value. + * * If an object is provided for `callback` the created "_.where" style callback * will return `true` for elements that have the properties of the given object, * else `false`. @@ -3791,7 +4050,7 @@ var global=self;/** * @memberOf _ * @category Collections * @param {Array|Object|string} collection The collection to iterate over. - * @param {Function|Object|string} [callback=identity] The function called + * @param {Array|Function|Object|string} [callback=identity] The function called * per iteration. If a property name or object is provided it will be used * to create a "_.pluck" or "_.where" style callback, respectively. * @param {*} [thisArg] The `this` binding of `callback`. @@ -3804,19 +4063,37 @@ var global=self;/** * _.sortBy([1, 2, 3], function(num) { return this.sin(num); }, Math); * // => [3, 1, 2] * + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 }, + * { 'name': 'barney', 'age': 26 }, + * { 'name': 'fred', 'age': 30 } + * ]; + * * // using "_.pluck" callback shorthand - * _.sortBy(['banana', 'strawberry', 'apple'], 'length'); - * // => ['apple', 'banana', 'strawberry'] + * _.map(_.sortBy(characters, 'age'), _.values); + * // => [['barney', 26], ['fred', 30], ['barney', 36], ['fred', 40]] + * + * // sorting by multiple properties + * _.map(_.sortBy(characters, ['name', 'age']), _.values); + * // = > [['barney', 26], ['barney', 36], ['fred', 30], ['fred', 40]] */ function sortBy(collection, callback, thisArg) { var index = -1, + isArr = isArray(callback), length = collection ? collection.length : 0, result = Array(typeof length == 'number' ? length : 0); - callback = lodash.createCallback(callback, thisArg, 3); + if (!isArr) { + callback = lodash.createCallback(callback, thisArg, 3); + } forEach(collection, function(value, key, collection) { var object = result[++index] = getObject(); - object.criteria = callback(value, key, collection); + if (isArr) { + object.criteria = map(callback, function(key) { return value[key]; }); + } else { + (object.criteria = getArray())[0] = callback(value, key, collection); + } object.index = index; object.value = value; }); @@ -3826,6 +4103,9 @@ var global=self;/** while (length--) { var object = result[length]; result[length] = object.value; + if (!isArr) { + releaseArray(object.criteria); + } releaseObject(object); } return result; @@ -3861,20 +4141,20 @@ var global=self;/** * @type Function * @category Collections * @param {Array|Object|string} collection The collection to iterate over. - * @param {Object} properties The object of property values to filter by. + * @param {Object} props The object of property values to filter by. * @returns {Array} Returns a new array of elements that have the given properties. * @example * - * var stooges = [ - * { 'name': 'curly', 'age': 30, 'quotes': ['Oh, a wise guy, eh?', 'Poifect!'] }, - * { 'name': 'moe', 'age': 40, 'quotes': ['Spread out!', 'You knucklehead!'] } + * var characters = [ + * { 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }, + * { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] } * ]; * - * _.where(stooges, { 'age': 40 }); - * // => [{ 'name': 'moe', 'age': 40, 'quotes': ['Spread out!', 'You knucklehead!'] }] + * _.where(characters, { 'age': 36 }); + * // => [{ 'name': 'barney', 'age': 36, 'pets': ['hoppy'] }] * - * _.where(stooges, { 'quotes': ['Poifect!'] }); - * // => [{ 'name': 'curly', 'age': 30, 'quotes': ['Oh, a wise guy, eh?', 'Poifect!'] }] + * _.where(characters, { 'pets': ['dino'] }); + * // => [{ 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] }] */ var where = filter; @@ -3916,7 +4196,7 @@ var global=self;/** * @memberOf _ * @category Arrays * @param {Array} array The array to process. - * @param {...Array} [array] The arrays of values to exclude. + * @param {...Array} [values] The arrays of values to exclude. * @returns {Array} Returns a new array of filtered values. * @example * @@ -3924,39 +4204,20 @@ var global=self;/** * // => [1, 3, 4] */ function difference(array) { - var index = -1, - indexOf = getIndexOf(), - length = array ? array.length : 0, - seen = baseFlatten(arguments, true, true, 1), - result = []; - - var isLarge = length >= largeArraySize && indexOf === baseIndexOf; - - if (isLarge) { - var cache = createCache(seen); - if (cache) { - indexOf = cacheIndexOf; - seen = cache; - } else { - isLarge = false; - } - } - while (++index < length) { - var value = array[index]; - if (indexOf(seen, value) < 0) { - result.push(value); - } - } - if (isLarge) { - releaseObject(seen); - } - return result; + return baseDifference(array, baseFlatten(arguments, true, true, 1)); } /** * This method is like `_.find` except that it returns the index of the first * element that passes the callback check, instead of the element itself. * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * * @static * @memberOf _ * @category Arrays @@ -3968,9 +4229,23 @@ var global=self;/** * @returns {number} Returns the index of the found element, else `-1`. * @example * - * _.findIndex(['apple', 'banana', 'beet'], function(food) { - * return /^b/.test(food); + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': false }, + * { 'name': 'fred', 'age': 40, 'blocked': true }, + * { 'name': 'pebbles', 'age': 1, 'blocked': false } + * ]; + * + * _.findIndex(characters, function(chr) { + * return chr.age < 20; * }); + * // => 2 + * + * // using "_.where" callback shorthand + * _.findIndex(characters, { 'age': 36 }); + * // => 0 + * + * // using "_.pluck" callback shorthand + * _.findIndex(characters, 'blocked'); * // => 1 */ function findIndex(array, callback, thisArg) { @@ -3990,6 +4265,13 @@ var global=self;/** * This method is like `_.findIndex` except that it iterates over elements * of a `collection` from right to left. * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * * @static * @memberOf _ * @category Arrays @@ -4001,9 +4283,23 @@ var global=self;/** * @returns {number} Returns the index of the found element, else `-1`. * @example * - * _.findLastIndex(['apple', 'banana', 'beet'], function(food) { - * return /^b/.test(food); + * var characters = [ + * { 'name': 'barney', 'age': 36, 'blocked': true }, + * { 'name': 'fred', 'age': 40, 'blocked': false }, + * { 'name': 'pebbles', 'age': 1, 'blocked': true } + * ]; + * + * _.findLastIndex(characters, function(chr) { + * return chr.age > 30; * }); + * // => 1 + * + * // using "_.where" callback shorthand + * _.findLastIndex(characters, { 'age': 36 }); + * // => 0 + * + * // using "_.pluck" callback shorthand + * _.findLastIndex(characters, 'blocked'); * // => 2 */ function findLastIndex(array, callback, thisArg) { @@ -4054,24 +4350,19 @@ var global=self;/** * }); * // => [1, 2] * - * var food = [ - * { 'name': 'banana', 'organic': true }, - * { 'name': 'beet', 'organic': false }, + * var characters = [ + * { 'name': 'barney', 'blocked': true, 'employer': 'slate' }, + * { 'name': 'fred', 'blocked': false, 'employer': 'slate' }, + * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' } * ]; * * // using "_.pluck" callback shorthand - * _.first(food, 'organic'); - * // => [{ 'name': 'banana', 'organic': true }] - * - * var food = [ - * { 'name': 'apple', 'type': 'fruit' }, - * { 'name': 'banana', 'type': 'fruit' }, - * { 'name': 'beet', 'type': 'vegetable' } - * ]; + * _.first(characters, 'blocked'); + * // => [{ 'name': 'barney', 'blocked': true, 'employer': 'slate' }] * * // using "_.where" callback shorthand - * _.first(food, { 'type': 'fruit' }); - * // => [{ 'name': 'apple', 'type': 'fruit' }, { 'name': 'banana', 'type': 'fruit' }] + * _.pluck(_.first(characters, { 'employer': 'slate' }), 'name'); + * // => ['barney', 'fred'] */ function first(array, callback, thisArg) { var n = 0, @@ -4124,20 +4415,20 @@ var global=self;/** * _.flatten([1, [2], [3, [[4]]]], true); * // => [1, 2, 3, [[4]]]; * - * var stooges = [ - * { 'name': 'curly', 'quotes': ['Oh, a wise guy, eh?', 'Poifect!'] }, - * { 'name': 'moe', 'quotes': ['Spread out!', 'You knucklehead!'] } + * var characters = [ + * { 'name': 'barney', 'age': 30, 'pets': ['hoppy'] }, + * { 'name': 'fred', 'age': 40, 'pets': ['baby puss', 'dino'] } * ]; * * // using "_.pluck" callback shorthand - * _.flatten(stooges, 'quotes'); - * // => ['Oh, a wise guy, eh?', 'Poifect!', 'Spread out!', 'You knucklehead!'] + * _.flatten(characters, 'pets'); + * // => ['hoppy', 'baby puss', 'dino'] */ function flatten(array, isShallow, callback, thisArg) { // juggle arguments if (typeof isShallow != 'boolean' && isShallow != null) { thisArg = callback; - callback = !(thisArg && thisArg[isShallow] === array) ? isShallow : null; + callback = (typeof isShallow != 'function' && thisArg && thisArg[isShallow] === array) ? null : isShallow; isShallow = false; } if (callback != null) { @@ -4217,24 +4508,19 @@ var global=self;/** * }); * // => [1] * - * var food = [ - * { 'name': 'beet', 'organic': false }, - * { 'name': 'carrot', 'organic': true } + * var characters = [ + * { 'name': 'barney', 'blocked': false, 'employer': 'slate' }, + * { 'name': 'fred', 'blocked': true, 'employer': 'slate' }, + * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' } * ]; * * // using "_.pluck" callback shorthand - * _.initial(food, 'organic'); - * // => [{ 'name': 'beet', 'organic': false }] - * - * var food = [ - * { 'name': 'banana', 'type': 'fruit' }, - * { 'name': 'beet', 'type': 'vegetable' }, - * { 'name': 'carrot', 'type': 'vegetable' } - * ]; + * _.initial(characters, 'blocked'); + * // => [{ 'name': 'barney', 'blocked': false, 'employer': 'slate' }] * * // using "_.where" callback shorthand - * _.initial(food, { 'type': 'vegetable' }); - * // => [{ 'name': 'banana', 'type': 'fruit' }] + * _.pluck(_.initial(characters, { 'employer': 'na' }), 'name'); + * // => ['barney', 'fred'] */ function initial(array, callback, thisArg) { var n = 0, @@ -4260,29 +4546,34 @@ var global=self;/** * @memberOf _ * @category Arrays * @param {...Array} [array] The arrays to inspect. - * @returns {Array} Returns an array of composite values. + * @returns {Array} Returns an array of shared values. * @example * - * _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]); + * _.intersection([1, 2, 3], [5, 2, 1, 4], [2, 1]); * // => [1, 2] */ - function intersection(array) { - var args = arguments, - argsLength = args.length, + function intersection() { + var args = [], argsIndex = -1, + argsLength = arguments.length, caches = getArray(), - index = -1, indexOf = getIndexOf(), - length = array ? array.length : 0, - result = [], + trustIndexOf = indexOf === baseIndexOf, seen = getArray(); while (++argsIndex < argsLength) { - var value = args[argsIndex]; - caches[argsIndex] = indexOf === baseIndexOf && - (value ? value.length : 0) >= largeArraySize && - createCache(argsIndex ? args[argsIndex] : seen); + var value = arguments[argsIndex]; + if (isArray(value) || isArguments(value)) { + args.push(value); + caches.push(trustIndexOf && value.length >= largeArraySize && + createCache(argsIndex ? args[argsIndex] : seen)); + } } + var array = args[0], + index = -1, + length = array ? array.length : 0, + result = []; + outer: while (++index < length) { var cache = caches[0]; @@ -4347,24 +4638,19 @@ var global=self;/** * }); * // => [2, 3] * - * var food = [ - * { 'name': 'beet', 'organic': false }, - * { 'name': 'carrot', 'organic': true } + * var characters = [ + * { 'name': 'barney', 'blocked': false, 'employer': 'slate' }, + * { 'name': 'fred', 'blocked': true, 'employer': 'slate' }, + * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' } * ]; * * // using "_.pluck" callback shorthand - * _.last(food, 'organic'); - * // => [{ 'name': 'carrot', 'organic': true }] - * - * var food = [ - * { 'name': 'banana', 'type': 'fruit' }, - * { 'name': 'beet', 'type': 'vegetable' }, - * { 'name': 'carrot', 'type': 'vegetable' } - * ]; + * _.pluck(_.last(characters, 'blocked'), 'name'); + * // => ['fred', 'pebbles'] * * // using "_.where" callback shorthand - * _.last(food, { 'type': 'vegetable' }); - * // => [{ 'name': 'beet', 'type': 'vegetable' }, { 'name': 'carrot', 'type': 'vegetable' }] + * _.last(characters, { 'employer': 'na' }); + * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }] */ function last(array, callback, thisArg) { var n = 0, @@ -4390,6 +4676,13 @@ var global=self;/** * equality for comparisons, i.e. `===`. If `fromIndex` is negative, it is used * as the offset from the end of the collection. * + * If a property name is provided for `callback` the created "_.pluck" style + * callback will return the property value of the given element. + * + * If an object is provided for `callback` the created "_.where" style callback + * will return `true` for elements that have the properties of the given object, + * else `false`. + * * @static * @memberOf _ * @category Arrays @@ -4468,17 +4761,17 @@ var global=self;/** * @returns {Array} Returns a new range array. * @example * - * _.range(10); - * // => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + * _.range(4); + * // => [0, 1, 2, 3] * - * _.range(1, 11); - * // => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + * _.range(1, 5); + * // => [1, 2, 3, 4] * - * _.range(0, 30, 5); - * // => [0, 5, 10, 15, 20, 25] + * _.range(0, 20, 5); + * // => [0, 5, 10, 15] * - * _.range(0, -10, -1); - * // => [0, -1, -2, -3, -4, -5, -6, -7, -8, -9] + * _.range(0, -4, -1); + * // => [0, -1, -2, -3] * * _.range(1, 4, 0); * // => [1, 1, 1] @@ -4494,7 +4787,7 @@ var global=self;/** end = start; start = 0; } - // use `Array(length)` so engines, like Chakra and V8, avoid slower modes + // use `Array(length)` so engines like Chakra and V8 avoid slower modes // http://youtu.be/XAqIpGU8ZZk#t=17m25s var index = -1, length = nativeMax(0, ceil((end - start) / (step || 1))), @@ -4594,24 +4887,19 @@ var global=self;/** * }); * // => [3] * - * var food = [ - * { 'name': 'banana', 'organic': true }, - * { 'name': 'beet', 'organic': false }, + * var characters = [ + * { 'name': 'barney', 'blocked': true, 'employer': 'slate' }, + * { 'name': 'fred', 'blocked': false, 'employer': 'slate' }, + * { 'name': 'pebbles', 'blocked': true, 'employer': 'na' } * ]; * * // using "_.pluck" callback shorthand - * _.rest(food, 'organic'); - * // => [{ 'name': 'beet', 'organic': false }] - * - * var food = [ - * { 'name': 'apple', 'type': 'fruit' }, - * { 'name': 'banana', 'type': 'fruit' }, - * { 'name': 'beet', 'type': 'vegetable' } - * ]; + * _.pluck(_.rest(characters, 'blocked'), 'name'); + * // => ['fred', 'pebbles'] * * // using "_.where" callback shorthand - * _.rest(food, { 'type': 'fruit' }); - * // => [{ 'name': 'beet', 'type': 'vegetable' }] + * _.rest(characters, { 'employer': 'slate' }); + * // => [{ 'name': 'pebbles', 'blocked': true, 'employer': 'na' }] */ function rest(array, callback, thisArg) { if (typeof callback != 'number' && callback != null) { @@ -4702,13 +4990,13 @@ var global=self;/** * @memberOf _ * @category Arrays * @param {...Array} [array] The arrays to inspect. - * @returns {Array} Returns an array of composite values. + * @returns {Array} Returns an array of combined values. * @example * - * _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]); - * // => [1, 2, 3, 101, 10] + * _.union([1, 2, 3], [5, 2, 1, 4], [2, 1]); + * // => [1, 2, 3, 5, 4] */ - function union(array) { + function union() { return baseUniq(baseFlatten(arguments, true, true)); } @@ -4760,7 +5048,7 @@ var global=self;/** // juggle arguments if (typeof isSorted != 'boolean' && isSorted != null) { thisArg = callback; - callback = !(thisArg && thisArg[isSorted] === array) ? isSorted : null; + callback = (typeof isSorted != 'function' && thisArg && thisArg[isSorted] === array) ? null : isSorted; isSorted = false; } if (callback != null) { @@ -4785,7 +5073,39 @@ var global=self;/** * // => [2, 3, 4] */ function without(array) { - return difference(array, nativeSlice.call(arguments, 1)); + return baseDifference(array, slice(arguments, 1)); + } + + /** + * Creates an array that is the symmetric difference of the provided arrays. + * See http://en.wikipedia.org/wiki/Symmetric_difference. + * + * @static + * @memberOf _ + * @category Arrays + * @param {...Array} [array] The arrays to inspect. + * @returns {Array} Returns an array of values. + * @example + * + * _.xor([1, 2, 3], [5, 2, 1, 4]); + * // => [3, 5, 4] + * + * _.xor([1, 2, 5], [2, 3, 5], [3, 4, 5]); + * // => [1, 4, 5] + */ + function xor() { + var index = -1, + length = arguments.length; + + while (++index < length) { + var array = arguments[index]; + if (isArray(array) || isArguments(array)) { + var result = result + ? baseUniq(baseDifference(result, array).concat(baseDifference(array, result))) + : array; + } + } + return result || []; } /** @@ -4801,8 +5121,8 @@ var global=self;/** * @returns {Array} Returns a new array of grouped elements. * @example * - * _.zip(['moe', 'larry'], [30, 40], [true, false]); - * // => [['moe', 30, true], ['larry', 40, false]] + * _.zip(['fred', 'barney'], [30, 40], [true, false]); + * // => [['fred', 30, true], ['barney', 40, false]] */ function zip() { var array = arguments.length > 1 ? arguments : arguments[0], @@ -4831,14 +5151,17 @@ var global=self;/** * corresponding values. * @example * - * _.zipObject(['moe', 'larry'], [30, 40]); - * // => { 'moe': 30, 'larry': 40 } + * _.zipObject(['fred', 'barney'], [30, 40]); + * // => { 'fred': 30, 'barney': 40 } */ function zipObject(keys, values) { var index = -1, length = keys ? keys.length : 0, result = {}; + if (!values && length && !isArray(keys[0])) { + values = []; + } while (++index < length) { var key = keys[index]; if (values) { @@ -4905,14 +5228,14 @@ var global=self;/** * return greeting + ' ' + this.name; * }; * - * func = _.bind(func, { 'name': 'moe' }, 'hi'); + * func = _.bind(func, { 'name': 'fred' }, 'hi'); * func(); - * // => 'hi moe' + * // => 'hi fred' */ function bind(func, thisArg) { return arguments.length > 2 - ? createBound(func, 17, nativeSlice.call(arguments, 2), null, thisArg) - : createBound(func, 1, null, null, thisArg); + ? createWrapper(func, 17, slice(arguments, 2), null, thisArg) + : createWrapper(func, 1, null, null, thisArg); } /** @@ -4931,8 +5254,8 @@ var global=self;/** * @example * * var view = { - * 'label': 'docs', - * 'onClick': function() { console.log('clicked ' + this.label); } + * 'label': 'docs', + * 'onClick': function() { console.log('clicked ' + this.label); } * }; * * _.bindAll(view); @@ -4946,7 +5269,7 @@ var global=self;/** while (++index < length) { var key = funcs[index]; - object[key] = createBound(object[key], 1, null, null, object); + object[key] = createWrapper(object[key], 1, null, null, object); } return object; } @@ -4968,7 +5291,7 @@ var global=self;/** * @example * * var object = { - * 'name': 'moe', + * 'name': 'fred', * 'greet': function(greeting) { * return greeting + ' ' + this.name; * } @@ -4976,19 +5299,19 @@ var global=self;/** * * var func = _.bindKey(object, 'greet', 'hi'); * func(); - * // => 'hi moe' + * // => 'hi fred' * * object.greet = function(greeting) { - * return greeting + ', ' + this.name + '!'; + * return greeting + 'ya ' + this.name + '!'; * }; * * func(); - * // => 'hi, moe!' + * // => 'hiya fred!' */ function bindKey(object, key) { return arguments.length > 2 - ? createBound(key, 19, nativeSlice.call(arguments, 2), null, object) - : createBound(key, 3, null, null, object); + ? createWrapper(key, 19, slice(arguments, 2), null, object) + : createWrapper(key, 3, null, null, object); } /** @@ -5005,7 +5328,7 @@ var global=self;/** * @example * * var realNameMap = { - * 'curly': 'jerome' + * 'pebbles': 'penelope' * }; * * var format = function(name) { @@ -5018,8 +5341,8 @@ var global=self;/** * }; * * var welcome = _.compose(greet, format); - * welcome('curly'); - * // => 'Hiya Jerome!' + * welcome('pebbles'); + * // => 'Hiya Penelope!' */ function compose() { var funcs = arguments, @@ -5041,74 +5364,6 @@ var global=self;/** }; } - /** - * Produces a callback bound to an optional `thisArg`. If `func` is a property - * name the created callback will return the property value for a given element. - * If `func` is an object the created callback will return `true` for elements - * that contain the equivalent object properties, otherwise it will return `false`. - * - * @static - * @memberOf _ - * @category Functions - * @param {*} [func=identity] The value to convert to a callback. - * @param {*} [thisArg] The `this` binding of the created callback. - * @param {number} [argCount] The number of arguments the callback accepts. - * @returns {Function} Returns a callback function. - * @example - * - * var stooges = [ - * { 'name': 'moe', 'age': 40 }, - * { 'name': 'larry', 'age': 50 } - * ]; - * - * // wrap to create custom callback shorthands - * _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) { - * var match = /^(.+?)__([gl]t)(.+)$/.exec(callback); - * return !match ? func(callback, thisArg) : function(object) { - * return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3]; - * }; - * }); - * - * _.filter(stooges, 'age__gt45'); - * // => [{ 'name': 'larry', 'age': 50 }] - */ - function createCallback(func, thisArg, argCount) { - var type = typeof func; - if (func == null || type == 'function') { - return baseCreateCallback(func, thisArg, argCount); - } - // handle "_.pluck" style callback shorthands - if (type != 'object') { - return function(object) { - return object[func]; - }; - } - var props = keys(func), - key = props[0], - a = func[key]; - - // handle "_.where" style callback shorthands - if (props.length == 1 && a === a && !isObject(a)) { - // fast path the common case of providing an object with a single - // property containing a primitive value - return function(object) { - var b = object[key]; - return a === b && (a !== 0 || (1 / a == 1 / b)); - }; - } - return function(object) { - var length = props.length, - result = false; - - while (length--) { - if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) { - break; - } - } - return result; - }; - } - /** * Creates a function which accepts one or more arguments of `func` that when * invoked either executes `func` returning its result, if all `func` arguments @@ -5139,7 +5394,7 @@ var global=self;/** */ function curry(func, arity) { arity = typeof arity == 'number' ? arity : (+arity || func.length); - return createBound(func, 4, null, null, null, arity); + return createWrapper(func, 4, null, null, null, arity); } /** @@ -5216,6 +5471,9 @@ var global=self;/** if (isCalled) { lastCalled = now(); result = func.apply(thisArg, args); + if (!timeoutId && !maxTimeoutId) { + args = thisArg = null; + } } } else { timeoutId = setTimeout(delayed, remaining); @@ -5230,6 +5488,9 @@ var global=self;/** if (trailing || (maxWait !== wait)) { lastCalled = now(); result = func.apply(thisArg, args); + if (!timeoutId && !maxTimeoutId) { + args = thisArg = null; + } } }; @@ -5245,8 +5506,10 @@ var global=self;/** if (!maxTimeoutId && !leading) { lastCalled = stamp; } - var remaining = maxWait - (stamp - lastCalled); - if (remaining <= 0) { + var remaining = maxWait - (stamp - lastCalled), + isCalled = remaining <= 0; + + if (isCalled) { if (maxTimeoutId) { maxTimeoutId = clearTimeout(maxTimeoutId); } @@ -5257,12 +5520,19 @@ var global=self;/** maxTimeoutId = setTimeout(maxDelayed, remaining); } } - if (!timeoutId && wait !== maxWait) { + if (isCalled && timeoutId) { + timeoutId = clearTimeout(timeoutId); + } + else if (!timeoutId && wait !== maxWait) { timeoutId = setTimeout(delayed, wait); } if (leadingCall) { + isCalled = true; result = func.apply(thisArg, args); } + if (isCalled && !timeoutId && !maxTimeoutId) { + args = thisArg = null; + } return result; }; } @@ -5279,25 +5549,16 @@ var global=self;/** * @returns {number} Returns the timer id. * @example * - * _.defer(function() { console.log('deferred'); }); - * // returns from the function before 'deferred' is logged + * _.defer(function(text) { console.log(text); }, 'deferred'); + * // logs 'deferred' after one or more milliseconds */ function defer(func) { if (!isFunction(func)) { throw new TypeError; } - var args = nativeSlice.call(arguments, 1); + var args = slice(arguments, 1); return setTimeout(function() { func.apply(undefined, args); }, 1); } - // use `setImmediate` if available in Node.js - if (isV8 && moduleExports && typeof setImmediate == 'function') { - defer = function(func) { - if (!isFunction(func)) { - throw new TypeError; - } - return setImmediate.apply(context, arguments); - }; - } /** * Executes the `func` function after `wait` milliseconds. Additional arguments @@ -5312,15 +5573,14 @@ var global=self;/** * @returns {number} Returns the timer id. * @example * - * var log = _.bind(console.log, console); - * _.delay(log, 1000, 'logged later'); - * // => 'logged later' (Appears after one second.) + * _.delay(function(text) { console.log(text); }, 1000, 'later'); + * // => logs 'later' after one second */ function delay(func, wait) { if (!isFunction(func)) { throw new TypeError; } - var args = nativeSlice.call(arguments, 2); + var args = slice(arguments, 2); return setTimeout(function() { func.apply(undefined, args); }, wait); } @@ -5344,19 +5604,22 @@ var global=self;/** * return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2); * }); * + * fibonacci(9) + * // => 34 + * * var data = { - * 'moe': { 'name': 'moe', 'age': 40 }, - * 'curly': { 'name': 'curly', 'age': 60 } + * 'fred': { 'name': 'fred', 'age': 40 }, + * 'pebbles': { 'name': 'pebbles', 'age': 1 } * }; * * // modifying the result cache - * var stooge = _.memoize(function(name) { return data[name]; }, _.identity); - * stooge('curly'); - * // => { 'name': 'curly', 'age': 60 } + * var get = _.memoize(function(name) { return data[name]; }, _.identity); + * get('pebbles'); + * // => { 'name': 'pebbles', 'age': 1 } * - * stooge.cache.curly.name = 'jerome'; - * stooge('curly'); - * // => { 'name': 'jerome', 'age': 60 } + * get.cache.pebbles.name = 'penelope'; + * get('pebbles'); + * // => { 'name': 'penelope', 'age': 1 } */ function memoize(func, resolver) { if (!isFunction(func)) { @@ -5426,11 +5689,11 @@ var global=self;/** * * var greet = function(greeting, name) { return greeting + ' ' + name; }; * var hi = _.partial(greet, 'hi'); - * hi('moe'); - * // => 'hi moe' + * hi('fred'); + * // => 'hi fred' */ function partial(func) { - return createBound(func, 16, nativeSlice.call(arguments, 1)); + return createWrapper(func, 16, slice(arguments, 1)); } /** @@ -5461,7 +5724,7 @@ var global=self;/** * // => { '_': _, 'jq': $ } */ function partialRight(func) { - return createBound(func, 32, null, nativeSlice.call(arguments, 1)); + return createWrapper(func, 32, null, slice(arguments, 1)); } /** @@ -5512,8 +5775,7 @@ var global=self;/** debounceOptions.maxWait = wait; debounceOptions.trailing = trailing; - var result = debounce(func, wait, debounceOptions); - return result; + return debounce(func, wait, debounceOptions); } /** @@ -5530,26 +5792,106 @@ var global=self;/** * @returns {Function} Returns the new function. * @example * - * var hello = function(name) { return 'hello ' + name; }; - * hello = _.wrap(hello, function(func) { - * return 'before, ' + func('moe') + ', after'; + * var p = _.wrap(_.escape, function(func, text) { + * return '

' + func(text) + '

'; * }); - * hello(); - * // => 'before, hello moe, after' + * + * p('Fred, Wilma, & Pebbles'); + * // => '

Fred, Wilma, & Pebbles

' */ function wrap(value, wrapper) { - if (!isFunction(wrapper)) { - throw new TypeError; - } - return function() { - var args = [value]; - push.apply(args, arguments); - return wrapper.apply(this, args); - }; + return createWrapper(wrapper, 16, [value]); } /*--------------------------------------------------------------------------*/ + /** + * Creates a function that returns `value`. + * + * @static + * @memberOf _ + * @category Utilities + * @param {*} value The value to return from the new function. + * @returns {Function} Returns the new function. + * @example + * + * var object = { 'name': 'fred' }; + * var getter = _.constant(object); + * getter() === object; + * // => true + */ + function constant(value) { + return function() { + return value; + }; + } + + /** + * Produces a callback bound to an optional `thisArg`. If `func` is a property + * name the created callback will return the property value for a given element. + * If `func` is an object the created callback will return `true` for elements + * that contain the equivalent object properties, otherwise it will return `false`. + * + * @static + * @memberOf _ + * @category Utilities + * @param {*} [func=identity] The value to convert to a callback. + * @param {*} [thisArg] The `this` binding of the created callback. + * @param {number} [argCount] The number of arguments the callback accepts. + * @returns {Function} Returns a callback function. + * @example + * + * var characters = [ + * { 'name': 'barney', 'age': 36 }, + * { 'name': 'fred', 'age': 40 } + * ]; + * + * // wrap to create custom callback shorthands + * _.createCallback = _.wrap(_.createCallback, function(func, callback, thisArg) { + * var match = /^(.+?)__([gl]t)(.+)$/.exec(callback); + * return !match ? func(callback, thisArg) : function(object) { + * return match[2] == 'gt' ? object[match[1]] > match[3] : object[match[1]] < match[3]; + * }; + * }); + * + * _.filter(characters, 'age__gt38'); + * // => [{ 'name': 'fred', 'age': 40 }] + */ + function createCallback(func, thisArg, argCount) { + var type = typeof func; + if (func == null || type == 'function') { + return baseCreateCallback(func, thisArg, argCount); + } + // handle "_.pluck" style callback shorthands + if (type != 'object') { + return property(func); + } + var props = keys(func), + key = props[0], + a = func[key]; + + // handle "_.where" style callback shorthands + if (props.length == 1 && a === a && !isObject(a)) { + // fast path the common case of providing an object with a single + // property containing a primitive value + return function(object) { + var b = object[key]; + return a === b && (a !== 0 || (1 / a == 1 / b)); + }; + } + return function(object) { + var length = props.length, + result = false; + + while (length--) { + if (!(result = baseIsEqual(object[props[length]], func[props[length]], null, true))) { + break; + } + } + return result; + }; + } + /** * Converts the characters `&`, `<`, `>`, `"`, and `'` in `string` to their * corresponding HTML entities. @@ -5561,8 +5903,8 @@ var global=self;/** * @returns {string} Returns the escaped string. * @example * - * _.escape('Moe, Larry & Curly'); - * // => 'Moe, Larry & Curly' + * _.escape('Fred, Wilma, & Pebbles'); + * // => 'Fred, Wilma, & Pebbles' */ function escape(string) { return string == null ? '' : String(string).replace(reUnescapedHtml, escapeHtmlChar); @@ -5578,8 +5920,8 @@ var global=self;/** * @returns {*} Returns `value`. * @example * - * var moe = { 'name': 'moe' }; - * moe === _.identity(moe); + * var object = { 'name': 'fred' }; + * _.identity(object) === object; * // => true */ function identity(value) { @@ -5587,51 +5929,71 @@ var global=self;/** } /** - * Adds function properties of a source object to the `lodash` function and - * chainable wrapper. + * Adds function properties of a source object to the destination object. + * If `object` is a function methods will be added to its prototype as well. * * @static * @memberOf _ * @category Utilities - * @param {Object} object The object of function properties to add to `lodash`. - * @param {Object} object The object of function properties to add to `lodash`. + * @param {Function|Object} [object=lodash] object The destination object. + * @param {Object} source The object of functions to add. + * @param {Object} [options] The options object. + * @param {boolean} [options.chain=true] Specify whether the functions added are chainable. * @example * - * _.mixin({ - * 'capitalize': function(string) { - * return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase(); - * } - * }); + * function capitalize(string) { + * return string.charAt(0).toUpperCase() + string.slice(1).toLowerCase(); + * } * - * _.capitalize('moe'); - * // => 'Moe' + * _.mixin({ 'capitalize': capitalize }); + * _.capitalize('fred'); + * // => 'Fred' * - * _('moe').capitalize(); - * // => 'Moe' + * _('fred').capitalize().value(); + * // => 'Fred' + * + * _.mixin({ 'capitalize': capitalize }, { 'chain': false }); + * _('fred').capitalize(); + * // => 'Fred' */ - function mixin(object, source) { - var ctor = object, - isFunc = !source || isFunction(ctor); + function mixin(object, source, options) { + var chain = true, + methodNames = source && functions(source); - if (!source) { + if (!source || (!options && !methodNames.length)) { + if (options == null) { + options = source; + } ctor = lodashWrapper; source = object; object = lodash; + methodNames = functions(source); } - forEach(functions(source), function(methodName) { + if (options === false) { + chain = false; + } else if (isObject(options) && 'chain' in options) { + chain = options.chain; + } + var ctor = object, + isFunc = isFunction(ctor); + + forEach(methodNames, function(methodName) { var func = object[methodName] = source[methodName]; if (isFunc) { ctor.prototype[methodName] = function() { - var value = this.__wrapped__, + var chainAll = this.__chain__, + value = this.__wrapped__, args = [value]; push.apply(args, arguments); var result = func.apply(object, args); - if (value && typeof value == 'object' && value === result) { - return this; + if (chain || chainAll) { + if (value === result && isObject(result)) { + return this; + } + result = new ctor(result); + result.__chain__ = chainAll; } - result = new ctor(result); - result.__chain__ = this.__chain__; return result; }; } @@ -5655,6 +6017,39 @@ var global=self;/** return this; } + /** + * A no-operation function. + * + * @static + * @memberOf _ + * @category Utilities + * @example + * + * var object = { 'name': 'fred' }; + * _.noop(object) === undefined; + * // => true + */ + function noop() { + // no operation performed + } + + /** + * Gets the number of milliseconds that have elapsed since the Unix epoch + * (1 January 1970 00:00:00 UTC). + * + * @static + * @memberOf _ + * @category Utilities + * @example + * + * var stamp = _.now(); + * _.defer(function() { console.log(_.now() - stamp); }); + * // => logs the number of milliseconds it took for the deferred function to be called + */ + var now = isNative(now = Date.now) && now || function() { + return new Date().getTime(); + }; + /** * Converts the given value into an integer of the specified radix. * If `radix` is `undefined` or `0` a `radix` of `10` is used unless the @@ -5675,10 +6070,40 @@ var global=self;/** * // => 8 */ var parseInt = nativeParseInt(whitespace + '08') == 8 ? nativeParseInt : function(value, radix) { - // Firefox and Opera still follow the ES3 specified implementation of `parseInt` + // Firefox < 21 and Opera < 15 follow the ES3 specified implementation of `parseInt` return nativeParseInt(isString(value) ? value.replace(reLeadingSpacesAndZeros, '') : value, radix || 0); }; + /** + * Creates a "_.pluck" style function, which returns the `key` value of a + * given object. + * + * @static + * @memberOf _ + * @category Utilities + * @param {string} key The name of the property to retrieve. + * @returns {Function} Returns the new function. + * @example + * + * var characters = [ + * { 'name': 'fred', 'age': 40 }, + * { 'name': 'barney', 'age': 36 } + * ]; + * + * var getName = _.property('name'); + * + * _.map(characters, getName); + * // => ['barney', 'fred'] + * + * _.sortBy(characters, getName); + * // => [{ 'name': 'barney', 'age': 36 }, { 'name': 'fred', 'age': 40 }] + */ + function property(key) { + return function(object) { + return object[key]; + }; + } + /** * Produces a random number between `min` and `max` (inclusive). If only one * argument is provided a number between `0` and the given number will be @@ -5730,14 +6155,15 @@ var global=self;/** } else { max = +max || 0; } - var rand = nativeRandom(); - return (floating || min % 1 || max % 1) - ? nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1)))), max) - : min + floor(rand * (max - min + 1)); + if (floating || min % 1 || max % 1) { + var rand = nativeRandom(); + return nativeMin(min + (rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1)))), max); + } + return baseRandom(min, max); } /** - * Resolves the value of `property` on `object`. If `property` is a function + * Resolves the value of property `key` on `object`. If `key` is a function * it will be invoked with the `this` binding of `object` and its result returned, * else the property value is returned. If `object` is falsey then `undefined` * is returned. @@ -5746,7 +6172,7 @@ var global=self;/** * @memberOf _ * @category Utilities * @param {Object} object The object to inspect. - * @param {string} property The property to get the value of. + * @param {string} key The name of the property to resolve. * @returns {*} Returns the resolved value. * @example * @@ -5763,10 +6189,10 @@ var global=self;/** * _.result(object, 'stuff'); * // => 'nonsense' */ - function result(object, property) { + function result(object, key) { if (object) { - var value = object[property]; - return isFunction(value) ? object[property]() : value; + var value = object[key]; + return isFunction(value) ? object[key]() : value; } } @@ -5778,7 +6204,7 @@ var global=self;/** * debugging. See http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/#toc-sourceurl * * For more information on precompiling templates see: - * http://lodash.com/#custom-builds + * http://lodash.com/custom-builds * * For more information on Chrome extension sandboxes see: * http://developer.chrome.com/stable/extensions/sandboxingEval.html @@ -5801,8 +6227,8 @@ var global=self;/** * * // using the "interpolate" delimiter to create a compiled template * var compiled = _.template('hello <%= name %>'); - * compiled({ 'name': 'moe' }); - * // => 'hello moe' + * compiled({ 'name': 'fred' }); + * // => 'hello fred' * * // using the "escape" delimiter to escape HTML in data property values * _.template('<%- value %>', { 'value': '