vendor/assets/javascripts/lodash.compat.js in lodash-rails-1.2.1 vs vendor/assets/javascripts/lodash.compat.js in lodash-rails-1.3.1
- old
+ new
@@ -1,8 +1,8 @@
/**
* @license
- * Lo-Dash 1.2.1 (Custom Build) <http://lodash.com/>
+ * Lo-Dash 1.3.1 (Custom Build) <http://lodash.com/>
* Build: `lodash -o ./dist/lodash.compat.js`
* Copyright 2012-2013 The Dojo Foundation <http://dojofoundation.org/>
* Based on Underscore.js 1.4.4 <http://underscorejs.org/>
* Copyright 2009-2013 Jeremy Ashkenas, DocumentCloud Inc.
* Available under MIT license <http://lodash.com/license>
@@ -10,34 +10,29 @@
;(function(window) {
/** Used as a safe reference for `undefined` in pre ES5 environments */
var undefined;
- /** Detect free variable `exports` */
- var freeExports = typeof exports == 'object' && exports;
+ /** Used to pool arrays and objects used internally */
+ var arrayPool = [],
+ objectPool = [];
- /** Detect free variable `module` */
- var freeModule = typeof module == 'object' && module && module.exports == freeExports && module;
-
- /** Detect free variable `global`, from Node.js or Browserified code, and use it as `window` */
- var freeGlobal = typeof global == 'object' && global;
- if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) {
- window = freeGlobal;
- }
-
/** Used to generate unique IDs */
var idCounter = 0;
/** Used internally to indicate various things */
var indicatorObject = {};
/** Used to prefix keys to avoid issues with `__proto__` and properties on `Object.prototype` */
var keyPrefix = +new Date + '';
/** Used as the size when optimizations are enabled for large arrays */
- var largeArraySize = 200;
+ var largeArraySize = 75;
+ /** Used as the max size of the `arrayPool` and `objectPool` */
+ var maxPoolSize = 40;
+
/** Used to match empty string literals in compiled template source */
var reEmptyStringLeading = /\b__p \+= '';/g,
reEmptyStringMiddle = /\b(__p \+=) '' \+/g,
reEmptyStringTrailing = /(__e\(.*?\)|\b__t\)) \+\n'';/g;
@@ -54,10 +49,13 @@
var reFlags = /\w*$/;
/** Used to match "interpolate" template delimiters */
var reInterpolate = /<%=([\s\S]+?)%>/g;
+ /** Used to detect functions containing a `this` reference */
+ var reThis = (reThis = /\bthis\b/) && reThis.test(runInContext) && reThis;
+
/** Used to detect and test whitespace */
var whitespace = (
// whitespace
' \t\x0B\f\xA0\ufeff' +
@@ -80,13 +78,13 @@
/** Used to match unescaped characters in compiled string literals */
var reUnescapedString = /['\n\r\t\u2028\u2029\\]/g;
/** Used to assign default `context` object properties */
var contextProps = [
- 'Array', 'Boolean', 'Date', 'Function', 'Math', 'Number', 'Object', 'RegExp',
- 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN', 'parseInt',
- 'setImmediate', 'setTimeout'
+ 'Array', 'Boolean', 'Date', 'Error', 'Function', 'Math', 'Number', 'Object',
+ 'RegExp', 'String', '_', 'attachEvent', 'clearTimeout', 'isFinite', 'isNaN',
+ 'parseInt', 'setImmediate', 'setTimeout'
];
/** Used to fix the JScript [[DontEnum]] bug */
var shadowedProps = [
'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable',
@@ -99,10 +97,11 @@
/** `Object#toString` result shortcuts */
var argsClass = '[object Arguments]',
arrayClass = '[object Array]',
boolClass = '[object Boolean]',
dateClass = '[object Date]',
+ errorClass = '[object Error]',
funcClass = '[object Function]',
numberClass = '[object Number]',
objectClass = '[object Object]',
regexpClass = '[object RegExp]',
stringClass = '[object String]';
@@ -134,13 +133,311 @@
'\t': 't',
'\u2028': 'u2028',
'\u2029': 'u2029'
};
+ /** Detect free variable `exports` */
+ var freeExports = objectTypes[typeof exports] && exports;
+
+ /** Detect free variable `module` */
+ var freeModule = objectTypes[typeof module] && module && module.exports == freeExports && module;
+
+ /** Detect free variable `global`, from Node.js or Browserified code, and use it as `window` */
+ var freeGlobal = objectTypes[typeof global] && global;
+ if (freeGlobal && (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal)) {
+ window = freeGlobal;
+ }
+
/*--------------------------------------------------------------------------*/
/**
+ * A basic implementation of `_.indexOf` without support for binary searches
+ * or `fromIndex` constraints.
+ *
+ * @private
+ * @param {Array} array The array to search.
+ * @param {Mixed} value The value to search for.
+ * @param {Number} [fromIndex=0] The index to search from.
+ * @returns {Number} Returns the index of the matched value or `-1`.
+ */
+ function basicIndexOf(array, value, fromIndex) {
+ var index = (fromIndex || 0) - 1,
+ length = array.length;
+
+ while (++index < length) {
+ if (array[index] === value) {
+ return index;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * An implementation of `_.contains` for cache objects that mimics the return
+ * signature of `_.indexOf` by returning `0` if the value is found, else `-1`.
+ *
+ * @private
+ * @param {Object} cache The cache object to inspect.
+ * @param {Mixed} value The value to search for.
+ * @returns {Number} Returns `0` if `value` is found, else `-1`.
+ */
+ function cacheIndexOf(cache, value) {
+ var type = typeof value;
+ cache = cache.cache;
+
+ if (type == 'boolean' || value == null) {
+ return cache[value];
+ }
+ if (type != 'number' && type != 'string') {
+ type = 'object';
+ }
+ var key = type == 'number' ? value : keyPrefix + value;
+ cache = cache[type] || (cache[type] = {});
+
+ return type == 'object'
+ ? (cache[key] && basicIndexOf(cache[key], value) > -1 ? 0 : -1)
+ : (cache[key] ? 0 : -1);
+ }
+
+ /**
+ * Adds a given `value` to the corresponding cache object.
+ *
+ * @private
+ * @param {Mixed} value The value to add to the cache.
+ */
+ function cachePush(value) {
+ var cache = this.cache,
+ type = typeof value;
+
+ if (type == 'boolean' || value == null) {
+ cache[value] = true;
+ } else {
+ if (type != 'number' && type != 'string') {
+ type = 'object';
+ }
+ var key = type == 'number' ? value : keyPrefix + value,
+ typeCache = cache[type] || (cache[type] = {});
+
+ if (type == 'object') {
+ if ((typeCache[key] || (typeCache[key] = [])).push(value) == this.array.length) {
+ cache[type] = false;
+ }
+ } else {
+ typeCache[key] = true;
+ }
+ }
+ }
+
+ /**
+ * Used by `_.max` and `_.min` as the default `callback` when a given
+ * `collection` is a string value.
+ *
+ * @private
+ * @param {String} value The character to inspect.
+ * @returns {Number} Returns the code unit of given character.
+ */
+ function charAtCallback(value) {
+ return value.charCodeAt(0);
+ }
+
+ /**
+ * Used by `sortBy` to compare transformed `collection` values, stable sorting
+ * them in ascending order.
+ *
+ * @private
+ * @param {Object} a The object to compare to `b`.
+ * @param {Object} b The object to compare to `a`.
+ * @returns {Number} Returns the sort order indicator of `1` or `-1`.
+ */
+ function compareAscending(a, b) {
+ var ai = a.index,
+ bi = b.index;
+
+ a = a.criteria;
+ b = b.criteria;
+
+ // ensure a stable sort in V8 and other engines
+ // http://code.google.com/p/v8/issues/detail?id=90
+ if (a !== b) {
+ if (a > b || typeof a == 'undefined') {
+ return 1;
+ }
+ if (a < b || typeof b == 'undefined') {
+ return -1;
+ }
+ }
+ return ai < bi ? -1 : 1;
+ }
+
+ /**
+ * Creates a cache object to optimize linear searches of large arrays.
+ *
+ * @private
+ * @param {Array} [array=[]] The array to search.
+ * @returns {Null|Object} Returns the cache object or `null` if caching should not be used.
+ */
+ function createCache(array) {
+ var index = -1,
+ length = array.length;
+
+ var cache = getObject();
+ cache['false'] = cache['null'] = cache['true'] = cache['undefined'] = false;
+
+ var result = getObject();
+ result.array = array;
+ result.cache = cache;
+ result.push = cachePush;
+
+ while (++index < length) {
+ result.push(array[index]);
+ }
+ return cache.object === false
+ ? (releaseObject(result), null)
+ : result;
+ }
+
+ /**
+ * Used by `template` to escape characters for inclusion in compiled
+ * string literals.
+ *
+ * @private
+ * @param {String} match The matched character to escape.
+ * @returns {String} Returns the escaped character.
+ */
+ function escapeStringChar(match) {
+ return '\\' + stringEscapes[match];
+ }
+
+ /**
+ * Gets an array from the array pool or creates a new one if the pool is empty.
+ *
+ * @private
+ * @returns {Array} The array from the pool.
+ */
+ function getArray() {
+ return arrayPool.pop() || [];
+ }
+
+ /**
+ * Gets an object from the object pool or creates a new one if the pool is empty.
+ *
+ * @private
+ * @returns {Object} The object from the pool.
+ */
+ function getObject() {
+ return objectPool.pop() || {
+ 'args': '',
+ 'array': null,
+ 'bottom': '',
+ 'cache': null,
+ 'criteria': null,
+ 'false': false,
+ 'firstArg': '',
+ 'index': 0,
+ 'init': '',
+ 'leading': false,
+ 'loop': '',
+ 'maxWait': 0,
+ 'null': false,
+ 'number': null,
+ 'object': null,
+ 'push': null,
+ 'shadowedProps': null,
+ 'string': null,
+ 'top': '',
+ 'trailing': false,
+ 'true': false,
+ 'undefined': false,
+ 'useHas': false,
+ 'useKeys': false,
+ 'value': null
+ };
+ }
+
+ /**
+ * Checks if `value` is a DOM node in IE < 9.
+ *
+ * @private
+ * @param {Mixed} value The value to check.
+ * @returns {Boolean} Returns `true` if the `value` is a DOM node, else `false`.
+ */
+ function isNode(value) {
+ // IE < 9 presents DOM nodes as `Object` objects except they have `toString`
+ // methods that are `typeof` "string" and still can coerce nodes to strings
+ return typeof value.toString != 'function' && typeof (value + '') == 'string';
+ }
+
+ /**
+ * A no-operation function.
+ *
+ * @private
+ */
+ function noop() {
+ // no operation performed
+ }
+
+ /**
+ * Releases the given `array` back to the array pool.
+ *
+ * @private
+ * @param {Array} [array] The array to release.
+ */
+ function releaseArray(array) {
+ array.length = 0;
+ if (arrayPool.length < maxPoolSize) {
+ arrayPool.push(array);
+ }
+ }
+
+ /**
+ * Releases the given `object` back to the object pool.
+ *
+ * @private
+ * @param {Object} [object] The object to release.
+ */
+ function releaseObject(object) {
+ var cache = object.cache;
+ if (cache) {
+ releaseObject(cache);
+ }
+ object.array = object.cache = object.criteria = object.object = object.number = object.string = object.value = null;
+ if (objectPool.length < maxPoolSize) {
+ objectPool.push(object);
+ }
+ }
+
+ /**
+ * Slices the `collection` from the `start` index up to, but not including,
+ * the `end` index.
+ *
+ * Note: This function is used, instead of `Array#slice`, to support node lists
+ * in IE < 9 and to ensure dense arrays are returned.
+ *
+ * @private
+ * @param {Array|Object|String} collection The collection to slice.
+ * @param {Number} start The start index.
+ * @param {Number} end The end index.
+ * @returns {Array} Returns the new array.
+ */
+ function slice(array, start, end) {
+ start || (start = 0);
+ if (typeof end == 'undefined') {
+ end = array ? array.length : 0;
+ }
+ var index = -1,
+ length = end - start || 0,
+ result = Array(length < 0 ? 0 : length);
+
+ while (++index < length) {
+ result[index] = array[start + index];
+ }
+ return result;
+ }
+
+ /*--------------------------------------------------------------------------*/
+
+ /**
* Create a new `lodash` function using the given `context` object.
*
* @static
* @memberOf _
* @category Utilities
@@ -156,46 +453,59 @@
/** Native constructor references */
var Array = context.Array,
Boolean = context.Boolean,
Date = context.Date,
+ Error = context.Error,
Function = context.Function,
Math = context.Math,
Number = context.Number,
Object = context.Object,
RegExp = context.RegExp,
String = context.String,
TypeError = context.TypeError;
- /** Used for `Array` and `Object` method references */
- var arrayRef = Array(),
- objectRef = Object();
+ /**
+ * Used for `Array` method references.
+ *
+ * Normally `Array.prototype` would suffice, however, using an array literal
+ * avoids issues in Narwhal.
+ */
+ var arrayRef = [];
+ /** Used for native method references */
+ var errorProto = Error.prototype,
+ objectProto = Object.prototype,
+ stringProto = String.prototype;
+
/** Used to restore the original `_` reference in `noConflict` */
var oldDash = context._;
/** Used to detect if a method is native */
var reNative = RegExp('^' +
- String(objectRef.valueOf)
+ String(objectProto.valueOf)
.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
.replace(/valueOf|for [^\]]+/g, '.+?') + '$'
);
/** Native method shortcuts */
var ceil = Math.ceil,
clearTimeout = context.clearTimeout,
concat = arrayRef.concat,
floor = Math.floor,
+ fnToString = Function.prototype.toString,
getPrototypeOf = reNative.test(getPrototypeOf = Object.getPrototypeOf) && getPrototypeOf,
- hasOwnProperty = objectRef.hasOwnProperty,
+ hasOwnProperty = objectProto.hasOwnProperty,
push = arrayRef.push,
+ propertyIsEnumerable = objectProto.propertyIsEnumerable,
setImmediate = context.setImmediate,
setTimeout = context.setTimeout,
- toString = objectRef.toString;
+ toString = objectProto.toString;
/* 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,
nativeIsFinite = context.isFinite,
nativeIsNaN = context.isNaN,
nativeKeys = reNative.test(nativeKeys = Object.keys) && nativeKeys,
nativeMax = Math.max,
@@ -211,15 +521,35 @@
/** Used to lookup a built-in constructor by [[Class]] */
var ctorByClass = {};
ctorByClass[arrayClass] = Array;
ctorByClass[boolClass] = Boolean;
ctorByClass[dateClass] = Date;
+ ctorByClass[funcClass] = Function;
ctorByClass[objectClass] = Object;
ctorByClass[numberClass] = Number;
ctorByClass[regexpClass] = RegExp;
ctorByClass[stringClass] = String;
+ /** Used to avoid iterating non-enumerable properties in IE < 9 */
+ var nonEnumProps = {};
+ nonEnumProps[arrayClass] = nonEnumProps[dateClass] = nonEnumProps[numberClass] = { 'constructor': true, 'toLocaleString': true, 'toString': true, 'valueOf': true };
+ nonEnumProps[boolClass] = nonEnumProps[stringClass] = { 'constructor': true, 'toString': true, 'valueOf': true };
+ nonEnumProps[errorClass] = nonEnumProps[funcClass] = nonEnumProps[regexpClass] = { 'constructor': true, 'toString': true };
+ nonEnumProps[objectClass] = { 'constructor': true };
+
+ (function() {
+ var length = shadowedProps.length;
+ while (length--) {
+ var prop = shadowedProps[length];
+ for (var className in nonEnumProps) {
+ if (hasOwnProperty.call(nonEnumProps, className) && !hasOwnProperty.call(nonEnumProps[className], prop)) {
+ nonEnumProps[className][prop] = false;
+ }
+ }
+ }
+ }());
+
/*--------------------------------------------------------------------------*/
/**
* Creates a `lodash` object, which wraps the given `value`, to enable method
* chaining.
@@ -237,12 +567,12 @@
* `defer`, `delay`, `difference`, `filter`, `flatten`, `forEach`, `forIn`,
* `forOwn`, `functions`, `groupBy`, `initial`, `intersection`, `invert`,
* `invoke`, `keys`, `map`, `max`, `memoize`, `merge`, `min`, `object`, `omit`,
* `once`, `pairs`, `partial`, `partialRight`, `pick`, `pluck`, `push`, `range`,
* `reject`, `rest`, `reverse`, `shuffle`, `slice`, `sort`, `sortBy`, `splice`,
- * `tap`, `throttle`, `times`, `toArray`, `union`, `uniq`, `unshift`, `unzip`,
- * `values`, `where`, `without`, `wrap`, and `zip`
+ * `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`, `has`,
* `identity`, `indexOf`, `isArguments`, `isArray`, `isBoolean`, `isDate`,
* `isElement`, `isEmpty`, `isEqual`, `isFinite`, `isFunction`, `isNaN`,
@@ -254,10 +584,11 @@
* The wrapper functions `first` and `last` return wrapped values when `n` is
* passed, otherwise they return unwrapped values.
*
* @name _
* @constructor
+ * @alias chain
* @category Chaining
* @param {Mixed} value The value to wrap in a `lodash` instance.
* @returns {Object} Returns a `lodash` instance.
* @example
*
@@ -286,10 +617,23 @@
? value
: new lodashWrapper(value);
}
/**
+ * A fast path for creating `lodash` wrapper objects.
+ *
+ * @private
+ * @param {Mixed} value The value to wrap in a `lodash` instance.
+ * @returns {Object} Returns a `lodash` instance.
+ */
+ function lodashWrapper(value) {
+ this.__wrapped__ = value;
+ }
+ // ensure `new lodashWrapper` is an instance of `lodash`
+ lodashWrapper.prototype = lodash.prototype;
+
+ /**
* An object used to flag environments features.
*
* @static
* @memberOf _
* @type Object
@@ -320,21 +664,30 @@
* @type Boolean
*/
support.argsClass = isArguments(arguments);
/**
+ * Detect if `name` or `message` properties of `Error.prototype` are
+ * enumerable by default. (IE < 9, Safari < 5.1)
+ *
+ * @memberOf _.support
+ * @type Boolean
+ */
+ support.enumErrorProps = propertyIsEnumerable.call(errorProto, 'message') || propertyIsEnumerable.call(errorProto, 'name');
+
+ /**
* Detect if `prototype` properties are enumerable by default.
*
* Firefox < 3.6, Opera > 9.50 - Opera < 11.60, and Safari < 5.1
* (if the prototype or a property on the prototype has been set)
* incorrectly sets a function's `prototype` property [[Enumerable]]
* value to `true`.
*
* @memberOf _.support
* @type Boolean
*/
- support.enumPrototypes = ctor.propertyIsEnumerable('prototype');
+ support.enumPrototypes = propertyIsEnumerable.call(ctor, 'prototype');
/**
* Detect if `Function#bind` exists and is inferred to be fast (all but V8).
*
* @memberOf _.support
@@ -486,81 +839,84 @@
(obj.firstArg) +
', result = ' +
(obj.init) +
';\nif (!iterable) return result;\n' +
(obj.top) +
- ';\n';
- if (obj.arrays) {
- __p += 'var length = iterable.length; index = -1;\nif (' +
- (obj.arrays) +
+ ';';
+ if (obj.array) {
+ __p += '\nvar length = iterable.length; index = -1;\nif (' +
+ (obj.array) +
') { ';
if (support.unindexedChars) {
__p += '\n if (isString(iterable)) {\n iterable = iterable.split(\'\')\n } ';
}
__p += '\n while (++index < length) {\n ' +
(obj.loop) +
- '\n }\n}\nelse { ';
- } else if (support.nonEnumArgs) {
+ ';\n }\n}\nelse { ';
+ } else if (support.nonEnumArgs) {
__p += '\n var length = iterable.length; index = -1;\n if (length && isArguments(iterable)) {\n while (++index < length) {\n index += \'\';\n ' +
(obj.loop) +
- '\n }\n } else { ';
+ ';\n }\n } else { ';
}
if (support.enumPrototypes) {
__p += '\n var skipProto = typeof iterable == \'function\';\n ';
}
+ if (support.enumErrorProps) {
+ __p += '\n var skipErrorProps = iterable === errorProto || iterable instanceof Error;\n ';
+ }
+
+ var conditions = []; if (support.enumPrototypes) { conditions.push('!(skipProto && index == "prototype")'); } if (support.enumErrorProps) { conditions.push('!(skipErrorProps && (index == "message" || index == "name"))'); }
+
if (obj.useHas && obj.useKeys) {
- __p += '\n var ownIndex = -1,\n ownProps = objectTypes[typeof iterable] ? keys(iterable) : [],\n length = ownProps.length;\n\n while (++ownIndex < length) {\n index = ownProps[ownIndex];\n ';
- if (support.enumPrototypes) {
- __p += 'if (!(skipProto && index == \'prototype\')) {\n ';
+ __p += '\n var ownIndex = -1,\n ownProps = objectTypes[typeof iterable] && keys(iterable),\n length = ownProps ? ownProps.length : 0;\n\n while (++ownIndex < length) {\n index = ownProps[ownIndex];\n';
+ if (conditions.length) {
+ __p += ' if (' +
+ (conditions.join(' && ')) +
+ ') {\n ';
}
__p +=
- (obj.loop);
- if (support.enumPrototypes) {
- __p += '}\n';
+ (obj.loop) +
+ '; ';
+ if (conditions.length) {
+ __p += '\n }';
}
- __p += ' } ';
+ __p += '\n } ';
} else {
- __p += '\n for (index in iterable) {';
- if (support.enumPrototypes || obj.useHas) {
- __p += '\n if (';
- if (support.enumPrototypes) {
- __p += '!(skipProto && index == \'prototype\')';
- } if (support.enumPrototypes && obj.useHas) {
- __p += ' && ';
- } if (obj.useHas) {
- __p += 'hasOwnProperty.call(iterable, index)';
+ __p += '\n for (index in iterable) {\n';
+ if (obj.useHas) { conditions.push("hasOwnProperty.call(iterable, index)"); } if (conditions.length) {
+ __p += ' if (' +
+ (conditions.join(' && ')) +
+ ') {\n ';
}
- __p += ') { ';
- }
__p +=
(obj.loop) +
'; ';
- if (support.enumPrototypes || obj.useHas) {
+ if (conditions.length) {
__p += '\n }';
}
__p += '\n } ';
if (support.nonEnumShadows) {
- __p += '\n\n var ctor = iterable.constructor;\n ';
- for (var k = 0; k < 7; k++) {
- __p += '\n index = \'' +
+ __p += '\n\n if (iterable !== objectProto) {\n var ctor = iterable.constructor,\n isProto = iterable === (ctor && ctor.prototype),\n className = iterable === stringProto ? stringClass : iterable === errorProto ? errorClass : toString.call(iterable),\n nonEnum = nonEnumProps[className];\n ';
+ for (k = 0; k < 7; k++) {
+ __p += '\n index = \'' +
(obj.shadowedProps[k]) +
- '\';\n if (';
- if (obj.shadowedProps[k] == 'constructor') {
- __p += '!(ctor && ctor.prototype === iterable) && ';
- }
- __p += 'hasOwnProperty.call(iterable, index)) {\n ' +
+ '\';\n if ((!(isProto && nonEnum[index]) && hasOwnProperty.call(iterable, index))';
+ if (!obj.useHas) {
+ __p += ' || (!nonEnum[index] && iterable[index] !== objectProto[index])';
+ }
+ __p += ') {\n ' +
(obj.loop) +
- '\n } ';
+ ';\n } ';
}
-
+ __p += '\n } ';
}
}
- if (obj.arrays || support.nonEnumArgs) {
+ if (obj.array || support.nonEnumArgs) {
__p += '\n}';
}
__p +=
(obj.bottom) +
';\nreturn result';
@@ -584,95 +940,23 @@
/** Reusable iterator options shared by `each`, `forIn`, and `forOwn` */
var eachIteratorOptions = {
'args': 'collection, callback, thisArg',
'top': "callback = callback && typeof thisArg == 'undefined' ? callback : lodash.createCallback(callback, thisArg)",
- 'arrays': "typeof length == 'number'",
+ 'array': "typeof length == 'number'",
'loop': 'if (callback(iterable[index], index, collection) === false) return result'
};
/** Reusable iterator options for `forIn` and `forOwn` */
var forOwnIteratorOptions = {
'top': 'if (!objectTypes[typeof iterable]) return result;\n' + eachIteratorOptions.top,
- 'arrays': false
+ 'array': false
};
/*--------------------------------------------------------------------------*/
/**
- * Creates a function optimized to search large arrays for a given `value`,
- * starting at `fromIndex`, using strict equality for comparisons, i.e. `===`.
- *
- * @private
- * @param {Array} array The array to search.
- * @param {Mixed} value The value to search for.
- * @returns {Boolean} Returns `true`, if `value` is found, else `false`.
- */
- function cachedContains(array) {
- var length = array.length,
- isLarge = length >= largeArraySize;
-
- if (isLarge) {
- var cache = {},
- index = -1;
-
- while (++index < length) {
- var key = keyPrefix + array[index];
- (cache[key] || (cache[key] = [])).push(array[index]);
- }
- }
- return function(value) {
- if (isLarge) {
- var key = keyPrefix + value;
- return cache[key] && indexOf(cache[key], value) > -1;
- }
- return indexOf(array, value) > -1;
- }
- }
-
- /**
- * Used by `_.max` and `_.min` as the default `callback` when a given
- * `collection` is a string value.
- *
- * @private
- * @param {String} value The character to inspect.
- * @returns {Number} Returns the code unit of given character.
- */
- function charAtCallback(value) {
- return value.charCodeAt(0);
- }
-
- /**
- * Used by `sortBy` to compare transformed `collection` values, stable sorting
- * them in ascending order.
- *
- * @private
- * @param {Object} a The object to compare to `b`.
- * @param {Object} b The object to compare to `a`.
- * @returns {Number} Returns the sort order indicator of `1` or `-1`.
- */
- function compareAscending(a, b) {
- var ai = a.index,
- bi = b.index;
-
- a = a.criteria;
- b = b.criteria;
-
- // ensure a stable sort in V8 and other engines
- // http://code.google.com/p/v8/issues/detail?id=90
- if (a !== b) {
- if (a > b || typeof a == 'undefined') {
- return 1;
- }
- if (a < b || typeof b == 'undefined') {
- return -1;
- }
- }
- return ai < bi ? -1 : 1;
- }
-
- /**
* Creates a function that, when called, invokes `func` with the `this` binding
* of `thisArg` and prepends any `partialArgs` to the arguments passed to the
* bound function.
*
* @private
@@ -714,13 +998,11 @@
? (args = nativeSlice.call(args), rightIndicator ? args.concat(partialArgs) : partialArgs.concat(args))
: partialArgs;
}
if (this instanceof bound) {
// ensure `new bound` is an instance of `func`
- noop.prototype = func.prototype;
- thisBinding = new noop;
- noop.prototype = null;
+ thisBinding = createObject(func.prototype);
// mimic the constructor's `return` behavior
// http://es5.github.com/#x13.2.2
var result = func.apply(thisBinding, args);
return isObject(result) ? result : thisBinding;
@@ -733,33 +1015,30 @@
/**
* Creates compiled iteration functions.
*
* @private
* @param {Object} [options1, options2, ...] The compile options object(s).
- * arrays - A string of code to determine if the iterable is an array or array-like.
+ * array - A string of code to determine if the iterable is an array or array-like.
* useHas - A boolean to specify using `hasOwnProperty` checks in the object loop.
* useKeys - A boolean to specify using `_.keys` for own property iteration.
* args - A string of comma separated arguments the iteration function will accept.
* top - A string of code to execute before the iteration branches.
* loop - A string of code to execute in the object loop.
* bottom - A string of code to execute after the iteration branches.
* @returns {Function} Returns the compiled function.
*/
function createIterator() {
- var data = {
- // data properties
- 'shadowedProps': shadowedProps,
- // iterator options
- 'arrays': 'isArray(iterable)',
- 'bottom': '',
- 'init': 'iterable',
- 'loop': '',
- 'top': '',
- 'useHas': true,
- 'useKeys': !!keys
- };
+ var data = getObject();
+ // data properties
+ data.shadowedProps = shadowedProps;
+ // iterator options
+ data.array = data.bottom = data.loop = data.top = '';
+ data.init = 'iterable';
+ data.useHas = true;
+ data.useKeys = !!keys;
+
// merge options into a template data object
for (var object, index = 0; object = arguments[index]; index++) {
for (var key in object) {
data[key] = object[key];
}
@@ -767,32 +1046,47 @@
var args = data.args;
data.firstArg = /^[^,]+/.exec(args)[0];
// create the function factory
var factory = Function(
- 'hasOwnProperty, isArguments, isArray, isString, keys, ' +
- 'lodash, objectTypes',
+ 'errorClass, errorProto, hasOwnProperty, isArguments, isArray, ' +
+ 'isString, keys, lodash, objectProto, objectTypes, nonEnumProps, ' +
+ 'stringClass, stringProto, toString',
'return function(' + args + ') {\n' + iteratorTemplate(data) + '\n}'
);
+
+ releaseObject(data);
+
// return the compiled function
return factory(
- hasOwnProperty, isArguments, isArray, isString, keys,
- lodash, objectTypes
+ errorClass, errorProto, hasOwnProperty, isArguments, isArray,
+ isString, keys, lodash, objectProto, objectTypes, nonEnumProps,
+ stringClass, stringProto, toString
);
}
/**
- * Used by `template` to escape characters for inclusion in compiled
- * string literals.
+ * Creates a new object with the specified `prototype`.
*
* @private
- * @param {String} match The matched character to escape.
- * @returns {String} Returns the escaped character.
+ * @param {Object} prototype The prototype object.
+ * @returns {Object} Returns the new object.
*/
- function escapeStringChar(match) {
- return '\\' + stringEscapes[match];
+ function createObject(prototype) {
+ return isObject(prototype) ? nativeCreate(prototype) : {};
}
+ // fallback for browsers without `Object.create`
+ if (!nativeCreate) {
+ var createObject = function(prototype) {
+ if (isObject(prototype)) {
+ noop.prototype = prototype;
+ var result = new noop;
+ noop.prototype = null;
+ }
+ return result || {};
+ };
+ }
/**
* Used by `escape` to convert characters to HTML entities.
*
* @private
@@ -802,114 +1096,86 @@
function escapeHtmlChar(match) {
return htmlEscapes[match];
}
/**
- * Checks if `value` is a DOM node in IE < 9.
+ * Gets the appropriate "indexOf" function. If the `_.indexOf` method is
+ * customized, this method returns the custom method, otherwise it returns
+ * the `basicIndexOf` function.
*
* @private
- * @param {Mixed} value The value to check.
- * @returns {Boolean} Returns `true` if the `value` is a DOM node, else `false`.
+ * @returns {Function} Returns the "indexOf" function.
*/
- function isNode(value) {
- // IE < 9 presents DOM nodes as `Object` objects except they have `toString`
- // methods that are `typeof` "string" and still can coerce nodes to strings
- return typeof value.toString != 'function' && typeof (value + '') == 'string';
+ function getIndexOf(array, value, fromIndex) {
+ var result = (result = lodash.indexOf) === indexOf ? basicIndexOf : result;
+ return result;
}
/**
- * A fast path for creating `lodash` wrapper objects.
+ * Creates a function that juggles arguments, allowing argument overloading
+ * for `_.flatten` and `_.uniq`, before passing them to the given `func`.
*
* @private
- * @param {Mixed} value The value to wrap in a `lodash` instance.
- * @returns {Object} Returns a `lodash` instance.
+ * @param {Function} func The function to wrap.
+ * @returns {Function} Returns the new function.
*/
- function lodashWrapper(value) {
- this.__wrapped__ = value;
+ function overloadWrapper(func) {
+ return function(array, flag, callback, thisArg) {
+ // juggle arguments
+ if (typeof flag != 'boolean' && flag != null) {
+ thisArg = callback;
+ callback = !(thisArg && thisArg[flag] === array) ? flag : undefined;
+ flag = false;
+ }
+ if (callback != null) {
+ callback = lodash.createCallback(callback, thisArg);
+ }
+ return func(array, flag, callback, thisArg);
+ };
}
- // ensure `new lodashWrapper` is an instance of `lodash`
- lodashWrapper.prototype = lodash.prototype;
/**
- * A no-operation function.
- *
- * @private
- */
- function noop() {
- // no operation performed
- }
-
- /**
* A fallback implementation of `isPlainObject` which checks if a given `value`
* is an object created by the `Object` constructor, assuming objects created
* by the `Object` constructor have no inherited enumerable properties and that
* there are no `Object.prototype` extensions.
*
* @private
* @param {Mixed} value The value to check.
* @returns {Boolean} Returns `true`, if `value` is a plain object, else `false`.
*/
function shimIsPlainObject(value) {
- // avoid non-objects and false positives for `arguments` objects
- var result = false;
- if (!(value && toString.call(value) == objectClass) || (!support.argsClass && isArguments(value))) {
- return result;
- }
- // check that the constructor is `Object` (i.e. `Object instanceof Object`)
- var ctor = value.constructor;
+ var ctor,
+ result;
- if (isFunction(ctor) ? ctor instanceof ctor : (support.nodeClass || !isNode(value))) {
- // IE < 9 iterates inherited properties before own properties. If the first
- // iterated property is an object's own property then there are no inherited
- // enumerable properties.
- if (support.ownLast) {
- forIn(value, function(value, key, object) {
- result = hasOwnProperty.call(object, key);
- return false;
- });
- return result === true;
- }
- // In most environments an object's own properties are iterated before
- // its inherited properties. If the last iterated property is an object's
- // own property then there are no inherited enumerable properties.
- forIn(value, function(value, key) {
- result = key;
+ // avoid non Object objects, `arguments` objects, and DOM elements
+ if (!(value && toString.call(value) == objectClass) ||
+ (ctor = value.constructor, isFunction(ctor) && !(ctor instanceof ctor)) ||
+ (!support.argsClass && isArguments(value)) ||
+ (!support.nodeClass && isNode(value))) {
+ return false;
+ }
+ // IE < 9 iterates inherited properties before own properties. If the first
+ // iterated property is an object's own property then there are no inherited
+ // enumerable properties.
+ if (support.ownLast) {
+ forIn(value, function(value, key, object) {
+ result = hasOwnProperty.call(object, key);
+ return false;
});
- return result === false || hasOwnProperty.call(value, result);
+ return result !== false;
}
- return result;
+ // In most environments an object's own properties are iterated before
+ // its inherited properties. If the last iterated property is an object's
+ // own property then there are no inherited enumerable properties.
+ forIn(value, function(value, key) {
+ result = key;
+ });
+ return result === undefined || hasOwnProperty.call(value, result);
}
/**
- * Slices the `collection` from the `start` index up to, but not including,
- * the `end` index.
- *
- * Note: This function is used, instead of `Array#slice`, to support node lists
- * in IE < 9 and to ensure dense arrays are returned.
- *
- * @private
- * @param {Array|Object|String} collection The collection to slice.
- * @param {Number} start The start index.
- * @param {Number} end The end index.
- * @returns {Array} Returns the new array.
- */
- function slice(array, start, end) {
- start || (start = 0);
- if (typeof end == 'undefined') {
- end = array ? array.length : 0;
- }
- var index = -1,
- length = end - start || 0,
- result = Array(length < 0 ? 0 : length);
-
- while (++index < length) {
- result[index] = array[start + index];
- }
- return result;
- }
-
- /**
* Used by `unescape` to convert HTML entities to characters.
*
* @private
* @param {String} match The matched character to unescape.
* @returns {String} Returns the unescaped character.
@@ -977,12 +1243,11 @@
*/
var shimKeys = createIterator({
'args': 'object',
'init': '[]',
'top': 'if (!(objectTypes[typeof object])) return result',
- 'loop': 'result.push(index)',
- 'arrays': false
+ 'loop': 'result.push(index)'
});
/**
* Creates an array composed of the own enumerable property names of `object`.
*
@@ -1019,11 +1284,11 @@
* @param {Array|Object|String} collection The collection to iterate over.
* @param {Function} [callback=identity] The function called per iteration.
* @param {Mixed} [thisArg] The `this` binding of `callback`.
* @returns {Array|Object|String} Returns `collection`.
*/
- var each = createIterator(eachIteratorOptions);
+ var basicEach = createIterator(eachIteratorOptions);
/**
* Used to convert characters to HTML entities:
*
* Though the `>` character is escaped for symmetry, characters like `>` and `/`
@@ -1132,11 +1397,11 @@
function clone(value, deep, callback, thisArg, stackA, stackB) {
var result = value;
// allows working with "Collections" methods without using their `callback`
// argument, `index|key`, for this method's `callback`
- if (typeof deep == 'function') {
+ if (typeof deep != 'boolean' && deep != null) {
thisArg = callback;
callback = deep;
deep = false;
}
if (typeof callback == 'function') {
@@ -1177,12 +1442,13 @@
case regexpClass:
return ctor(result.source, reFlags.exec(result));
}
// check for circular references and return corresponding clone
- stackA || (stackA = []);
- stackB || (stackB = []);
+ var initedStack = !stackA;
+ stackA || (stackA = getArray());
+ stackB || (stackB = getArray());
var length = stackA.length;
while (length--) {
if (stackA[length] == value) {
return stackB[length];
@@ -1204,24 +1470,28 @@
// and associate it with its clone
stackA.push(value);
stackB.push(result);
// recursively populate clone (susceptible to call stack limits)
- (isArr ? forEach : forOwn)(value, function(objValue, key) {
+ (isArr ? basicEach : forOwn)(value, function(objValue, key) {
result[key] = clone(objValue, deep, callback, undefined, stackA, stackB);
});
+ if (initedStack) {
+ releaseArray(stackA);
+ releaseArray(stackB);
+ }
return result;
}
/**
* Creates a deep clone of `value`. If a `callback` function is passed,
* it will be executed to produce the cloned values. If `callback` returns
* `undefined`, cloning will be handled by the method instead. The `callback`
* is bound to `thisArg` and invoked with one argument; (value).
*
- * Note: This function is loosely based on the structured clone algorithm. Functions
+ * Note: This method is loosely based on the structured clone algorithm. Functions
* and DOM nodes are **not** cloned. The enumerable properties of `arguments` objects and
* objects created by constructors other than `Object` are cloned to plain `Object` objects.
* See http://www.w3.org/TR/html5/infrastructure.html#internal-structured-cloning-algorithm.
*
* @static
@@ -1654,12 +1924,13 @@
}
}
// assume cyclic structures are equal
// the algorithm for detecting cyclic structures is adapted from ES 5.1
// section 15.12.3, abstract operation `JO` (http://es5.github.com/#x15.12.3)
- stackA || (stackA = []);
- stackB || (stackB = []);
+ var initedStack = !stackA;
+ stackA || (stackA = getArray());
+ stackB || (stackB = getArray());
var length = stackA.length;
while (length--) {
if (stackA[length] == a) {
return stackB[length] == b;
@@ -1717,10 +1988,14 @@
// `size` will be `-1` if `a` has more properties than `b`
return (result = --size > -1);
}
});
}
+ if (initedStack) {
+ releaseArray(stackA);
+ releaseArray(stackB);
+ }
return result;
}
/**
* Checks if `value` is, or can be coerced to, a finite number.
@@ -1800,11 +2075,11 @@
function isObject(value) {
// check if the value is the ECMAScript language type of Object
// http://es5.github.com/#x8
// and avoid a V8 bug
// http://code.google.com/p/v8/issues/detail?id=2291
- return value ? objectTypes[typeof value] : false;
+ return !!(value && objectTypes[typeof value]);
}
/**
* Checks if `value` is `NaN`.
*
@@ -1921,11 +2196,11 @@
*
* _.isRegExp(/moe/);
* // => true
*/
function isRegExp(value) {
- return value ? (objectTypes[typeof value] && toString.call(value) == regexpClass) : false;
+ return !!(value && objectTypes[typeof value]) && toString.call(value) == regexpClass;
}
/**
* Checks if `value` is a string.
*
@@ -2026,12 +2301,13 @@
if (deepIndicator === indicatorObject) {
var callback = args[3],
stackA = args[4],
stackB = args[5];
} else {
- stackA = [];
- stackB = [];
+ var initedStack = true;
+ stackA = getArray();
+ stackB = getArray();
// allows working with `_.reduce` and `_.reduceRight` without
// using their `callback` arguments, `index|key` and `collection`
if (typeof deepIndicator != 'number') {
length = args.length;
@@ -2093,10 +2369,15 @@
}
}
object[key] = value;
});
}
+
+ if (initedStack) {
+ releaseArray(stackA);
+ releaseArray(stackB);
+ }
return object;
}
/**
* Creates a shallow clone of `object` excluding the specified properties.
@@ -2123,11 +2404,12 @@
* return typeof value == 'number';
* });
* // => { 'name': 'moe' }
*/
function omit(object, callback, thisArg) {
- var isFunc = typeof callback == 'function',
+ var indexOf = getIndexOf(),
+ isFunc = typeof callback == 'function',
result = {};
if (isFunc) {
callback = lodash.createCallback(callback, thisArg);
} else {
@@ -2219,10 +2501,61 @@
}
return result;
}
/**
+ * An alternative to `_.reduce`, this method transforms an `object` to a new
+ * `accumulator` object which is the result of running each of its elements
+ * through the `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 {Function} [callback=identity] The function called per iteration.
+ * @param {Mixed} [accumulator] The custom accumulator value.
+ * @param {Mixed} [thisArg] The `this` binding of `callback`.
+ * @returns {Mixed} Returns the accumulated value.
+ * @example
+ *
+ * var squares = _.transform([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], function(result, num) {
+ * num *= num;
+ * if (num % 2) {
+ * return result.push(num) < 3;
+ * }
+ * });
+ * // => [1, 9, 25]
+ *
+ * var mapped = _.transform({ 'a': 1, 'b': 2, 'c': 3 }, function(result, num, key) {
+ * result[key] = num * 3;
+ * });
+ * // => { 'a': 3, 'b': 6, 'c': 9 }
+ */
+ function transform(object, callback, accumulator, thisArg) {
+ var isArr = isArray(object);
+ callback = lodash.createCallback(callback, thisArg, 4);
+
+ if (accumulator == null) {
+ if (isArr) {
+ accumulator = [];
+ } else {
+ var ctor = object && object.constructor,
+ proto = ctor && ctor.prototype;
+
+ accumulator = createObject(proto);
+ }
+ }
+ (isArr ? basicEach : forOwn)(object, function(value, index, object) {
+ return callback(accumulator, value, index, object);
+ });
+ return accumulator;
+ }
+
+ /**
* Creates an array composed of the own enumerable property values of `object`.
*
* @static
* @memberOf _
* @category Objects
@@ -2310,21 +2643,22 @@
* _.contains('curly', 'ur');
* // => true
*/
function contains(collection, target, fromIndex) {
var index = -1,
+ indexOf = getIndexOf(),
length = collection ? collection.length : 0,
result = false;
fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex) || 0;
- if (typeof length == 'number') {
+ if (length && typeof length == 'number') {
result = (isString(collection)
? collection.indexOf(target, fromIndex)
: indexOf(collection, target, fromIndex)
) > -1;
} else {
- each(collection, function(value) {
+ basicEach(collection, function(value) {
if (++index >= fromIndex) {
return !(result = value === target);
}
});
}
@@ -2428,11 +2762,11 @@
if (!(result = !!callback(collection[index], index, collection))) {
break;
}
}
} else {
- each(collection, function(value, index, collection) {
+ basicEach(collection, function(value, index, collection) {
return (result = !!callback(value, index, collection));
});
}
return result;
}
@@ -2490,11 +2824,11 @@
if (callback(value, index, collection)) {
result.push(value);
}
}
} else {
- each(collection, function(value, index, collection) {
+ basicEach(collection, function(value, index, collection) {
if (callback(value, index, collection)) {
result.push(value);
}
});
}
@@ -2513,11 +2847,11 @@
* will return `true` for elements that have the properties of the given object,
* else `false`.
*
* @static
* @memberOf _
- * @alias detect
+ * @alias detect, findWhere
* @category Collections
* @param {Array|Object|String} collection The collection to iterate over.
* @param {Function|Object|String} [callback=identity] The function called per
* iteration. If a property name or object is passed, it will be used to create
* a "_.pluck" or "_.where" style callback, respectively.
@@ -2557,11 +2891,11 @@
return value;
}
}
} else {
var result;
- each(collection, function(value, index, collection) {
+ basicEach(collection, function(value, index, collection) {
if (callback(value, index, collection)) {
result = value;
return false;
}
});
@@ -2600,11 +2934,11 @@
if (callback(collection[index], index, collection) === false) {
break;
}
}
} else {
- each(collection, callback, thisArg);
+ basicEach(collection, callback, thisArg);
}
return collection;
}
/**
@@ -2735,11 +3069,11 @@
if (isArray(collection)) {
while (++index < length) {
result[index] = callback(collection[index], index, collection);
}
} else {
- each(collection, function(value, key, collection) {
+ basicEach(collection, function(value, key, collection) {
result[++index] = callback(value, key, collection);
});
}
return result;
}
@@ -2800,11 +3134,11 @@
} else {
callback = (!callback && isString(collection))
? charAtCallback
: lodash.createCallback(callback, thisArg);
- each(collection, function(value, index, collection) {
+ basicEach(collection, function(value, index, collection) {
var current = callback(value, index, collection);
if (current > computed) {
computed = current;
result = value;
}
@@ -2869,11 +3203,11 @@
} else {
callback = (!callback && isString(collection))
? charAtCallback
: lodash.createCallback(callback, thisArg);
- each(collection, function(value, index, collection) {
+ basicEach(collection, function(value, index, collection) {
var current = callback(value, index, collection);
if (current < computed) {
computed = current;
result = value;
}
@@ -2947,11 +3281,11 @@
}
while (++index < length) {
accumulator = callback(accumulator, collection[index], index, collection);
}
} else {
- each(collection, function(value, index, collection) {
+ basicEach(collection, function(value, index, collection) {
accumulator = noaccum
? (noaccum = false, value)
: callback(accumulator, value, index, collection)
});
}
@@ -3150,11 +3484,11 @@
if ((result = callback(collection[index], index, collection))) {
break;
}
}
} else {
- each(collection, function(value, index, collection) {
+ basicEach(collection, function(value, index, collection) {
return !(result = callback(value, index, collection));
});
}
return !!result;
}
@@ -3199,21 +3533,22 @@
length = collection ? collection.length : 0,
result = Array(typeof length == 'number' ? length : 0);
callback = lodash.createCallback(callback, thisArg);
forEach(collection, function(value, key, collection) {
- result[++index] = {
- 'criteria': callback(value, key, collection),
- 'index': index,
- 'value': value
- };
+ var object = result[++index] = getObject();
+ object.criteria = callback(value, key, collection);
+ object.index = index;
+ object.value = value;
});
length = result.length;
result.sort(compareAscending);
while (length--) {
- result[length] = result[length].value;
+ var object = result[length];
+ result[length] = object.value;
+ releaseObject(object);
}
return result;
}
/**
@@ -3309,21 +3644,35 @@
* _.difference([1, 2, 3, 4, 5], [5, 2, 10]);
* // => [1, 3, 4]
*/
function difference(array) {
var index = -1,
+ indexOf = getIndexOf(),
length = array ? array.length : 0,
- flattened = concat.apply(arrayRef, nativeSlice.call(arguments, 1)),
- contains = cachedContains(flattened),
+ seen = concat.apply(arrayRef, nativeSlice.call(arguments, 1)),
result = [];
+ var isLarge = length >= largeArraySize && indexOf === basicIndexOf;
+
+ if (isLarge) {
+ var cache = createCache(seen);
+ if (cache) {
+ indexOf = cacheIndexOf;
+ seen = cache;
+ } else {
+ isLarge = false;
+ }
+ }
while (++index < length) {
var value = array[index];
- if (!contains(value)) {
+ if (indexOf(seen, value) < 0) {
result.push(value);
}
}
+ if (isLarge) {
+ releaseObject(seen);
+ }
return result;
}
/**
* This method is similar to `_.find`, except that it returns the index of
@@ -3475,24 +3824,15 @@
*
* // using "_.pluck" callback shorthand
* _.flatten(stooges, 'quotes');
* // => ['Oh, a wise guy, eh?', 'Poifect!', 'Spread out!', 'You knucklehead!']
*/
- function flatten(array, isShallow, callback, thisArg) {
+ var flatten = overloadWrapper(function flatten(array, isShallow, callback) {
var index = -1,
length = array ? array.length : 0,
result = [];
- // juggle arguments
- if (typeof isShallow != 'boolean' && isShallow != null) {
- thisArg = callback;
- callback = isShallow;
- isShallow = false;
- }
- if (callback != null) {
- callback = lodash.createCallback(callback, thisArg);
- }
while (++index < length) {
var value = array[index];
if (callback) {
value = callback(value, index, array);
}
@@ -3502,11 +3842,11 @@
} else {
result.push(value);
}
}
return result;
- }
+ });
/**
* Gets the index at which the first occurrence of `value` is found using
* strict equality for comparisons, i.e. `===`. If the `array` is already
* sorted, passing `true` for `fromIndex` will run a faster binary search.
@@ -3529,25 +3869,18 @@
*
* _.indexOf([1, 1, 2, 2, 3, 3], 2, true);
* // => 2
*/
function indexOf(array, value, fromIndex) {
- var index = -1,
- length = array ? array.length : 0;
-
if (typeof fromIndex == 'number') {
- index = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0) - 1;
+ var length = array ? array.length : 0;
+ fromIndex = (fromIndex < 0 ? nativeMax(0, length + fromIndex) : fromIndex || 0);
} else if (fromIndex) {
- index = sortedIndex(array, value);
+ var index = sortedIndex(array, value);
return array[index] === value ? index : -1;
}
- while (++index < length) {
- if (array[index] === value) {
- return index;
- }
- }
- return -1;
+ return array ? basicIndexOf(array, value, fromIndex) : -1;
}
/**
* Gets all but the last element of `array`. If a number `n` is passed, the
* last `n` elements are excluded from the result. If a `callback` function
@@ -3639,39 +3972,49 @@
* // => [1, 2]
*/
function intersection(array) {
var args = arguments,
argsLength = args.length,
- cache = { '0': {} },
+ argsIndex = -1,
+ caches = getArray(),
index = -1,
+ indexOf = getIndexOf(),
length = array ? array.length : 0,
- isLarge = length >= largeArraySize,
result = [],
- seen = result;
+ seen = getArray();
+ while (++argsIndex < argsLength) {
+ var value = args[argsIndex];
+ caches[argsIndex] = indexOf === basicIndexOf &&
+ (value ? value.length : 0) >= largeArraySize &&
+ createCache(argsIndex ? args[argsIndex] : seen);
+ }
outer:
while (++index < length) {
- var value = array[index];
- if (isLarge) {
- var key = keyPrefix + value;
- var inited = cache[0][key]
- ? !(seen = cache[0][key])
- : (seen = cache[0][key] = []);
- }
- if (inited || indexOf(seen, value) < 0) {
- if (isLarge) {
- seen.push(value);
- }
- var argsIndex = argsLength;
+ var cache = caches[0];
+ value = array[index];
+
+ if ((cache ? cacheIndexOf(cache, value) : indexOf(seen, value)) < 0) {
+ argsIndex = argsLength;
+ (cache || seen).push(value);
while (--argsIndex) {
- if (!(cache[argsIndex] || (cache[argsIndex] = cachedContains(args[argsIndex])))(value)) {
+ cache = caches[argsIndex];
+ if ((cache ? cacheIndexOf(cache, value) : indexOf(args[argsIndex], value)) < 0) {
continue outer;
}
}
result.push(value);
}
}
+ while (argsLength--) {
+ cache = caches[argsLength];
+ if (cache) {
+ releaseObject(cache);
+ }
+ }
+ releaseArray(caches);
+ releaseArray(seen);
return result;
}
/**
* Gets the last element of the `array`. If a number `n` is passed, the
@@ -3996,11 +4339,11 @@
/**
* Creates a duplicate-value-free version of the `array` using strict equality
* for comparisons, i.e. `===`. If the `array` is already sorted, passing `true`
* for `isSorted` will run a faster algorithm. If `callback` is passed, each
- * element of `array` is passed through a `callback` before uniqueness is computed.
+ * element of `array` is passed through the `callback` before uniqueness is computed.
* The `callback` is bound to `thisArg` and invoked with three arguments; (value, index, array).
*
* If a property name is passed for `callback`, the created "_.pluck" style
* callback will return the property value of the given element.
*
@@ -4025,63 +4368,61 @@
* // => [1, 2, 3]
*
* _.uniq([1, 1, 2, 2, 3], true);
* // => [1, 2, 3]
*
- * _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return Math.floor(num); });
- * // => [1, 2, 3]
+ * _.uniq(['A', 'b', 'C', 'a', 'B', 'c'], function(letter) { return letter.toLowerCase(); });
+ * // => ['A', 'b', 'C']
*
- * _.uniq([1, 2, 1.5, 3, 2.5], function(num) { return this.floor(num); }, Math);
- * // => [1, 2, 3]
+ * _.uniq([1, 2.5, 3, 1.5, 2, 3.5], function(num) { return this.floor(num); }, Math);
+ * // => [1, 2.5, 3]
*
* // using "_.pluck" callback shorthand
* _.uniq([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x');
* // => [{ 'x': 1 }, { 'x': 2 }]
*/
- function uniq(array, isSorted, callback, thisArg) {
+ var uniq = overloadWrapper(function(array, isSorted, callback) {
var index = -1,
+ indexOf = getIndexOf(),
length = array ? array.length : 0,
- result = [],
- seen = result;
+ result = [];
- // juggle arguments
- if (typeof isSorted != 'boolean' && isSorted != null) {
- thisArg = callback;
- callback = isSorted;
- isSorted = false;
- }
- // init value cache for large arrays
- var isLarge = !isSorted && length >= largeArraySize;
+ var isLarge = !isSorted && length >= largeArraySize && indexOf === basicIndexOf,
+ seen = (callback || isLarge) ? getArray() : result;
+
if (isLarge) {
- var cache = {};
+ var cache = createCache(seen);
+ if (cache) {
+ indexOf = cacheIndexOf;
+ seen = cache;
+ } else {
+ isLarge = false;
+ seen = callback ? seen : (releaseArray(seen), result);
+ }
}
- if (callback != null) {
- seen = [];
- callback = lodash.createCallback(callback, thisArg);
- }
while (++index < length) {
var value = array[index],
computed = callback ? callback(value, index, array) : value;
- if (isLarge) {
- var key = keyPrefix + computed;
- var inited = cache[key]
- ? !(seen = cache[key])
- : (seen = cache[key] = []);
- }
if (isSorted
? !index || seen[seen.length - 1] !== computed
- : inited || indexOf(seen, computed) < 0
+ : indexOf(seen, computed) < 0
) {
if (callback || isLarge) {
seen.push(computed);
}
result.push(value);
}
}
+ if (isLarge) {
+ releaseArray(seen.array);
+ releaseObject(seen);
+ } else if (callback) {
+ releaseArray(seen);
+ }
return result;
- }
+ });
/**
* The inverse of `_.zip`, this method splits groups of elements into arrays
* composed of elements from each group at their corresponding indexes.
*
@@ -4095,21 +4436,15 @@
* _.unzip([['moe', 30, true], ['larry', 40, false]]);
* // => [['moe', 'larry'], [30, 40], [true, false]];
*/
function unzip(array) {
var index = -1,
- length = array ? array.length : 0,
- tupleLength = length ? max(pluck(array, 'length')) : 0,
- result = Array(tupleLength);
+ length = array ? max(pluck(array, 'length')) : 0,
+ result = Array(length < 0 ? 0 : length);
while (++index < length) {
- var tupleIndex = -1,
- tuple = array[index];
-
- while (++tupleIndex < tupleLength) {
- (result[tupleIndex] || (result[tupleIndex] = Array(length)))[index] = tuple[tupleIndex];
- }
+ result[index] = pluck(array, index);
}
return result;
}
/**
@@ -4146,18 +4481,11 @@
*
* _.zip(['moe', 'larry'], [30, 40], [true, false]);
* // => [['moe', 30, true], ['larry', 40, false]]
*/
function zip(array) {
- var index = -1,
- length = array ? max(pluck(arguments, 'length')) : 0,
- result = Array(length);
-
- while (++index < length) {
- result[index] = pluck(arguments, index);
- }
- return result;
+ return array ? unzip(arguments) : [];
}
/**
* Creates an object composed from arrays of `keys` and `values`. Pass either
* a single two dimensional array, i.e. `[[key1, value1], [key2, value2]]`, or
@@ -4429,31 +4757,31 @@
}
}
return result;
};
}
- if (typeof thisArg != 'undefined') {
- if (argCount === 1) {
- return function(value) {
- return func.call(thisArg, value);
- };
- }
- if (argCount === 2) {
- return function(a, b) {
- return func.call(thisArg, a, b);
- };
- }
- if (argCount === 4) {
- return function(accumulator, value, index, collection) {
- return func.call(thisArg, accumulator, value, index, collection);
- };
- }
- return function(value, index, collection) {
- return func.call(thisArg, value, index, collection);
+ if (typeof thisArg == 'undefined' || (reThis && !reThis.test(fnToString.call(func)))) {
+ return func;
+ }
+ if (argCount === 1) {
+ return function(value) {
+ return func.call(thisArg, value);
};
}
- return func;
+ if (argCount === 2) {
+ return function(a, b) {
+ return func.call(thisArg, a, b);
+ };
+ }
+ if (argCount === 4) {
+ return function(accumulator, value, index, collection) {
+ return func.call(thisArg, accumulator, value, index, collection);
+ };
+ }
+ return function(value, index, collection) {
+ return func.call(thisArg, value, index, collection);
+ };
}
/**
* Creates a function that will delay the execution of `func` until after
* `wait` milliseconds have elapsed since the last time it was invoked. Pass
@@ -4470,10 +4798,11 @@
* @category Functions
* @param {Function} func The function to debounce.
* @param {Number} wait The number of milliseconds to delay.
* @param {Object} options The options object.
* [leading=false] A boolean to specify execution on the leading edge of the timeout.
+ * [maxWait] The maximum time `func` is allowed to be delayed before it's called.
* [trailing=true] A boolean to specify execution on the trailing edge of the timeout.
* @returns {Function} Returns the new debounced function.
* @example
*
* var lazyLayout = _.debounce(calculateLayout, 300);
@@ -4484,38 +4813,84 @@
* 'trailing': false
* });
*/
function debounce(func, wait, options) {
var args,
- inited,
result,
thisArg,
- timeoutId,
+ callCount = 0,
+ lastCalled = 0,
+ maxWait = false,
+ maxTimeoutId = null,
+ timeoutId = null,
trailing = true;
+ function clear() {
+ clearTimeout(maxTimeoutId);
+ clearTimeout(timeoutId);
+ callCount = 0;
+ maxTimeoutId = timeoutId = null;
+ }
+
function delayed() {
- inited = timeoutId = null;
- if (trailing) {
+ var isCalled = trailing && (!leading || callCount > 1);
+ clear();
+ if (isCalled) {
+ if (maxWait !== false) {
+ lastCalled = new Date;
+ }
result = func.apply(thisArg, args);
}
}
+
+ function maxDelayed() {
+ clear();
+ if (trailing || (maxWait !== wait)) {
+ lastCalled = new Date;
+ result = func.apply(thisArg, args);
+ }
+ }
+
+ wait = nativeMax(0, wait || 0);
if (options === true) {
var leading = true;
trailing = false;
- } else if (options && objectTypes[typeof options]) {
+ } else if (isObject(options)) {
leading = options.leading;
+ maxWait = 'maxWait' in options && nativeMax(wait, options.maxWait || 0);
trailing = 'trailing' in options ? options.trailing : trailing;
}
return function() {
args = arguments;
thisArg = this;
+ callCount++;
+
+ // avoid issues with Titanium and `undefined` timeout ids
+ // https://github.com/appcelerator/titanium_mobile/blob/3_1_0_GA/android/titanium/src/java/ti/modules/titanium/TitaniumModule.java#L185-L192
clearTimeout(timeoutId);
- if (!inited && leading) {
- inited = true;
- result = func.apply(thisArg, args);
+ if (maxWait === false) {
+ if (leading && callCount < 2) {
+ result = func.apply(thisArg, args);
+ }
} else {
+ var now = new Date;
+ if (!maxTimeoutId && !leading) {
+ lastCalled = now;
+ }
+ var remaining = maxWait - (now - lastCalled);
+ if (remaining <= 0) {
+ clearTimeout(maxTimeoutId);
+ maxTimeoutId = null;
+ lastCalled = now;
+ result = func.apply(thisArg, args);
+ }
+ else if (!maxTimeoutId) {
+ maxTimeoutId = setTimeout(maxDelayed, remaining);
+ }
+ }
+ if (wait !== maxWait) {
timeoutId = setTimeout(delayed, wait);
}
return result;
};
}
@@ -4569,11 +4944,12 @@
/**
* Creates a function that memoizes the result of `func`. If `resolver` is
* passed, it will be used to determine the cache key for storing the result
* based on the arguments passed to the memoized function. By default, the first
* argument passed to the memoized function is used as the cache key. The `func`
- * is executed with the `this` binding of the memoized function.
+ * is executed with the `this` binding of the memoized function. The result
+ * cache is exposed as the `cache` property on the memoized function.
*
* @static
* @memberOf _
* @category Functions
* @param {Function} func The function to have its output memoized.
@@ -4584,17 +4960,20 @@
* var fibonacci = _.memoize(function(n) {
* return n < 2 ? n : fibonacci(n - 1) + fibonacci(n - 2);
* });
*/
function memoize(func, resolver) {
- var cache = {};
- return function() {
- var key = keyPrefix + (resolver ? resolver.apply(this, arguments) : arguments[0]);
+ function memoized() {
+ var cache = memoized.cache,
+ key = keyPrefix + (resolver ? resolver.apply(this, arguments) : arguments[0]);
+
return hasOwnProperty.call(cache, key)
? cache[key]
: (cache[key] = func.apply(this, arguments));
- };
+ }
+ memoized.cache = {};
+ return memoized;
}
/**
* Creates a function that is restricted to execute `func` once. Repeat calls to
* the function will return the value of the first call. The `func` is executed
@@ -4710,51 +5089,27 @@
* jQuery('.interactive').on('click', _.throttle(renewToken, 300000, {
* 'trailing': false
* }));
*/
function throttle(func, wait, options) {
- var args,
- result,
- thisArg,
- timeoutId,
- lastCalled = 0,
- leading = true,
+ var leading = true,
trailing = true;
- function trailingCall() {
- timeoutId = null;
- if (trailing) {
- lastCalled = new Date;
- result = func.apply(thisArg, args);
- }
- }
if (options === false) {
leading = false;
- } else if (options && objectTypes[typeof options]) {
+ } else if (isObject(options)) {
leading = 'leading' in options ? options.leading : leading;
trailing = 'trailing' in options ? options.trailing : trailing;
}
- return function() {
- var now = new Date;
- if (!timeoutId && !leading) {
- lastCalled = now;
- }
- var remaining = wait - (now - lastCalled);
- args = arguments;
- thisArg = this;
+ options = getObject();
+ options.leading = leading;
+ options.maxWait = wait;
+ options.trailing = trailing;
- if (remaining <= 0) {
- clearTimeout(timeoutId);
- timeoutId = null;
- lastCalled = now;
- result = func.apply(thisArg, args);
- }
- else if (!timeoutId) {
- timeoutId = setTimeout(trailingCall, remaining);
- }
- return result;
- };
+ var result = debounce(func, wait, options);
+ releaseObject(options);
+ return result;
}
/**
* Creates a function that passes `value` to the `wrapper` function as its
* first argument. Additional arguments passed to the function are appended
@@ -4803,11 +5158,11 @@
function escape(string) {
return string == null ? '' : String(string).replace(reUnescapedHtml, escapeHtmlChar);
}
/**
- * This function returns the first argument passed to it.
+ * This method returns the first argument passed to it.
*
* @static
* @memberOf _
* @category Utilities
* @param {Mixed} value Any value.
@@ -4852,11 +5207,11 @@
var value = this.__wrapped__,
args = [value];
push.apply(args, arguments);
var result = func.apply(lodash, args);
- return (value && typeof value == 'object' && value == result)
+ return (value && typeof value == 'object' && value === result)
? this
: new lodashWrapper(result);
};
});
}
@@ -4926,12 +5281,17 @@
}
min = +min || 0;
if (max == null) {
max = min;
min = 0;
+ } else {
+ max = +max || 0;
}
- return min + floor(nativeRandom() * ((+max || 0) - min + 1));
+ var rand = nativeRandom();
+ return (min % 1 || max % 1)
+ ? min + nativeMin(rand * (max - min + parseFloat('1e-' + ((rand +'').length - 1))), max)
+ : min + floor(rand * (max - min + 1));
}
/**
* Resolves the value of `property` on `object`. If `property` is a function,
* it will be invoked with the `this` binding of `object` and its result returned,
@@ -5330,10 +5690,11 @@
lodash.sortBy = sortBy;
lodash.tap = tap;
lodash.throttle = throttle;
lodash.times = times;
lodash.toArray = toArray;
+ lodash.transform = transform;
lodash.union = union;
lodash.uniq = uniq;
lodash.unzip = unzip;
lodash.values = values;
lodash.where = where;
@@ -5354,10 +5715,14 @@
lodash.unique = uniq;
// add functions to `lodash.prototype`
mixin(lodash);
+ // add Underscore compat
+ lodash.chain = lodash;
+ lodash.prototype.chain = function() { return this; };
+
/*--------------------------------------------------------------------------*/
// add functions that return unwrapped values when chaining
lodash.clone = clone;
lodash.cloneDeep = cloneDeep;
@@ -5405,10 +5770,11 @@
// add aliases
lodash.all = every;
lodash.any = some;
lodash.detect = find;
+ lodash.findWhere = find;
lodash.foldl = reduce;
lodash.foldr = reduceRight;
lodash.include = contains;
lodash.inject = reduce;
@@ -5450,45 +5816,45 @@
*
* @static
* @memberOf _
* @type String
*/
- lodash.VERSION = '1.2.1';
+ lodash.VERSION = '1.3.1';
// add "Chaining" functions to the wrapper
lodash.prototype.toString = wrapperToString;
lodash.prototype.value = wrapperValueOf;
lodash.prototype.valueOf = wrapperValueOf;
// add `Array` functions that return unwrapped values
- each(['join', 'pop', 'shift'], function(methodName) {
+ basicEach(['join', 'pop', 'shift'], function(methodName) {
var func = arrayRef[methodName];
lodash.prototype[methodName] = function() {
return func.apply(this.__wrapped__, arguments);
};
});
// add `Array` functions that return the wrapped value
- each(['push', 'reverse', 'sort', 'unshift'], function(methodName) {
+ basicEach(['push', 'reverse', 'sort', 'unshift'], function(methodName) {
var func = arrayRef[methodName];
lodash.prototype[methodName] = function() {
func.apply(this.__wrapped__, arguments);
return this;
};
});
// add `Array` functions that return new wrapped values
- each(['concat', 'slice', 'splice'], function(methodName) {
+ basicEach(['concat', 'slice', 'splice'], function(methodName) {
var func = arrayRef[methodName];
lodash.prototype[methodName] = function() {
return new lodashWrapper(func.apply(this.__wrapped__, arguments));
};
});
// avoid array-like object bugs with `Array#shift` and `Array#splice`
// in Firefox < 10 and IE < 9
if (!support.spliceObjects) {
- each(['pop', 'shift', 'splice'], function(methodName) {
+ basicEach(['pop', 'shift', 'splice'], function(methodName) {
var func = arrayRef[methodName],
isSplice = methodName == 'splice';
lodash.prototype[methodName] = function() {
var value = this.__wrapped__,