Add toIterable to reduce support.unindexedChars use and optimize/simplify methods. [closes #601]

This commit is contained in:
John-David Dalton
2014-06-29 13:44:56 -07:00
parent 212282e77c
commit a9cc2fdb54

154
lodash.js
View File

@@ -630,7 +630,7 @@
var fnToString = Function.prototype.toString; var fnToString = Function.prototype.toString;
/** /**
* Used as the maximum length of an array-like object. * Used as the maximum length of an array-like value.
* See the [ES6 spec](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength) * See the [ES6 spec](http://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength)
* for more details. * for more details.
*/ */
@@ -757,8 +757,9 @@
* `isString`, `isUndefined`, `join`, `kebabCase`, `last`, `lastIndexOf`, * `isString`, `isUndefined`, `join`, `kebabCase`, `last`, `lastIndexOf`,
* `max`, `min`, `noConflict`, `now`, `pad`, `padLeft`, `padRight`, `parseInt`, * `max`, `min`, `noConflict`, `now`, `pad`, `padLeft`, `padRight`, `parseInt`,
* `pop`, `random`, `reduce`, `reduceRight`, `repeat`, `result`, `runInContext`, * `pop`, `random`, `reduce`, `reduceRight`, `repeat`, `result`, `runInContext`,
* `shift`, `size`, `snakeCase`, `some`, `sortedIndex`, `startsWith`, `template`, * `shift`, `size`, `snakeCase`, `some`, `sortedIndex`, `sortedLastIndex`,
* `trim`, `trimLeft`, `trimRight`, `trunc`, `unescape`, `uniqueId`, and `value` * `startsWith`, `template`, `trim`, `trimLeft`, `trimRight`, `trunc`,
* `unescape`, `uniqueId`, and `value`
* *
* The wrapper function `sample` will return a wrapped value when `n` is * The wrapper function `sample` will return a wrapped value when `n` is
* provided, otherwise it will return an unwrapped value. * provided, otherwise it will return an unwrapped value.
@@ -1226,7 +1227,7 @@
* @returns {*} Returns the value to assign to the destination object. * @returns {*} Returns the value to assign to the destination object.
*/ */
function assignOwnDefaults(objectValue, sourceValue, key, object) { function assignOwnDefaults(objectValue, sourceValue, key, object) {
return (!hasOwnProperty.call(object, key) || typeof objectValue == 'undefined') return (typeof objectValue == 'undefined' || !hasOwnProperty.call(object, key))
? sourceValue ? sourceValue
: objectValue : objectValue
} }
@@ -1589,21 +1590,17 @@
* @returns {Array|Object|string} Returns `collection`. * @returns {Array|Object|string} Returns `collection`.
*/ */
function baseEach(collection, iterator) { function baseEach(collection, iterator) {
var length = collection ? collection.length : 0;
if (!(typeof length == 'number' && length > -1 && length <= maxSafeInteger)) {
return baseForOwn(collection, iterator);
}
var index = -1, var index = -1,
iterable = collection, iterable = toIterable(collection);
length = collection ? collection.length : 0;
if (typeof length == 'number' && length > -1 && length <= maxSafeInteger) { while (++index < length) {
if (support.unindexedChars && isString(iterable)) { if (iterator(iterable[index], index, collection) === false) {
iterable = iterable.split(''); break;
} }
while (++index < length) {
if (iterator(iterable[index], index, collection) === false) {
break;
}
}
} else {
baseForOwn(collection, iterator);
} }
return collection; return collection;
} }
@@ -1618,20 +1615,15 @@
* @returns {Array|Object|string} Returns `collection`. * @returns {Array|Object|string} Returns `collection`.
*/ */
function baseEachRight(collection, iterator) { function baseEachRight(collection, iterator) {
var iterable = collection, var length = collection ? collection.length : 0;
length = collection ? collection.length : 0; if (!(typeof length == 'number' && length > -1 && length <= maxSafeInteger)) {
return baseForOwnRight(collection, iterator);
if (typeof length == 'number' && length > -1 && length <= maxSafeInteger) { }
if (support.unindexedChars && isString(iterable)) { var iterable = toIterable(collection);
iterable = iterable.split(''); while (length--) {
if (iterator(iterable[length], length, collection) === false) {
break;
} }
while (length--) {
if (iterator(iterable[length], length, collection) === false) {
break;
}
}
} else {
baseForOwnRight(collection, iterator);
} }
return collection; return collection;
} }
@@ -2104,6 +2096,7 @@
*/ */
function baseMerge(object, source, customizer, stackA, stackB) { function baseMerge(object, source, customizer, stackA, stackB) {
var isSrcArr = isArrayLike(source); var isSrcArr = isArrayLike(source);
(isSrcArr ? arrayEach : baseForOwn)(source, function(srcValue, key, source) { (isSrcArr ? arrayEach : baseForOwn)(source, function(srcValue, key, source) {
var isArr = srcValue && isArrayLike(srcValue), var isArr = srcValue && isArrayLike(srcValue),
isObj = srcValue && isPlainObject(srcValue), isObj = srcValue && isPlainObject(srcValue),
@@ -2383,6 +2376,7 @@
*/ */
function compileFunction(source, varNames, varValues, sourceURL) { function compileFunction(source, varNames, varValues, sourceURL) {
sourceURL = sourceURL ? ('\n/*\n//# sourceURL=' + sourceURL + '\n*/') : ''; sourceURL = sourceURL ? ('\n/*\n//# sourceURL=' + sourceURL + '\n*/') : '';
try { try {
// provide the compiled function's source by its `toString` method or // provide the compiled function's source by its `toString` method or
// the `source` property as a convenience for inlining compiled templates // the `source` property as a convenience for inlining compiled templates
@@ -2630,8 +2624,7 @@
argsLength = arguments.length, argsLength = arguments.length,
leftIndex = -1, leftIndex = -1,
leftLength = partialArgs.length, leftLength = partialArgs.length,
args = Array(argsLength + leftLength), args = Array(argsLength + leftLength);
thisBinding = isBind ? thisArg : this;
while (++leftIndex < leftLength) { while (++leftIndex < leftLength) {
args[leftIndex] = partialArgs[leftIndex]; args[leftIndex] = partialArgs[leftIndex];
@@ -2639,7 +2632,7 @@
while (argsLength--) { while (argsLength--) {
args[leftIndex++] = arguments[argsIndex++]; args[leftIndex++] = arguments[argsIndex++];
} }
return (this instanceof wrapper ? Ctor : func).apply(thisBinding, args); return (this instanceof wrapper ? Ctor : func).apply(isBind ? thisArg : this, args);
} }
return wrapper; return wrapper;
} }
@@ -2918,6 +2911,23 @@
return result; return result;
} }
/**
* Converts `collection` to an array if it is not an array-like value.
*
* @private
* @param {Array|Object|string} collection The collection to inspect.
* @returns {Array|Object} Returns the iterable object.
*/
function toIterable(collection) {
var length = collection ? collection.length : 0;
if (!(typeof length == 'number' && length > -1 && length <= maxSafeInteger)) {
return values(collection);
} else if (support.unindexedChars && isString(collection)) {
return collection.split('');
}
return collection || [];
}
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/** /**
@@ -3330,8 +3340,9 @@
/** /**
* Gets the index at which the first occurrence of `value` is found using * 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 * strict equality for comparisons, i.e. `===`. If `fromIndex` is negative,
* providing `true` for `fromIndex` performs a faster binary search. * it is used as the offset from the end of the collection. If `array` is
* sorted providing `true` for `fromIndex` performs a faster binary search.
* *
* @static * @static
* @memberOf _ * @memberOf _
@@ -3356,6 +3367,7 @@
*/ */
function indexOf(array, value, fromIndex) { function indexOf(array, value, fromIndex) {
var length = array ? array.length : 0; var length = array ? array.length : 0;
if (typeof fromIndex == 'number') { if (typeof fromIndex == 'number') {
fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0); fromIndex = fromIndex < 0 ? nativeMax(length + fromIndex, 0) : (fromIndex || 0);
} else if (fromIndex) { } else if (fromIndex) {
@@ -4234,8 +4246,10 @@
* // => ['fred', 'pebbles'] * // => ['fred', 'pebbles']
*/ */
function at(collection) { function at(collection) {
if (support.unindexedChars && isString(collection)) { var length = collection ? collection.length : 0;
collection = collection.split('');
if (typeof length == 'number' && length > -1 && length <= maxSafeInteger) {
collection = toIterable(collection);
} }
return baseAt(collection, baseFlatten(arguments, false, false, 1)); return baseAt(collection, baseFlatten(arguments, false, false, 1));
} }
@@ -4269,6 +4283,7 @@
*/ */
function contains(collection, target, fromIndex) { function contains(collection, target, fromIndex) {
var length = collection ? collection.length : 0; var length = collection ? collection.length : 0;
if (!(typeof length == 'number' && length > -1 && length <= maxSafeInteger)) { if (!(typeof length == 'number' && length > -1 && length <= maxSafeInteger)) {
collection = values(collection); collection = values(collection);
length = collection.length; length = collection.length;
@@ -5022,12 +5037,12 @@
* // => [4, 5, 2, 3, 0, 1] * // => [4, 5, 2, 3, 0, 1]
*/ */
function reduceRight(collection, iterator, accumulator, thisArg) { function reduceRight(collection, iterator, accumulator, thisArg) {
var noaccum = arguments.length < 3; var initFromCollection = arguments.length < 3;
iterator = lodash.callback(iterator, thisArg, 4); iterator = lodash.callback(iterator, thisArg, 4);
baseEachRight(collection, function(value, index, collection) { baseEachRight(collection, function(value, index, collection) {
accumulator = noaccum accumulator = initFromCollection
? (noaccum = false, value) ? (initFromCollection = false, value)
: iterator(accumulator, value, index, collection); : iterator(accumulator, value, index, collection);
}); });
return accumulator; return accumulator;
@@ -5095,14 +5110,9 @@
* // => [3, 1] * // => [3, 1]
*/ */
function sample(collection, n, guard) { function sample(collection, n, guard) {
var length = collection ? collection.length : 0; collection = toIterable(collection);
if (!(typeof length == 'number' && length > -1 && length <= maxSafeInteger)) { var length = collection.length;
collection = values(collection);
length = collection.length;
} else if (support.unindexedChars && isString(collection)) {
collection = collection.split('');
}
if (n == null || guard) { if (n == null || guard) {
return length > 0 ? collection[baseRandom(0, length - 1)] : undefined; return length > 0 ? collection[baseRandom(0, length - 1)] : undefined;
} }
@@ -5127,21 +5137,25 @@
* // => [4, 1, 3, 2] * // => [4, 1, 3, 2]
*/ */
function shuffle(collection) { function shuffle(collection) {
var index = -1, collection = toIterable(collection);
length = collection && collection.length,
result = Array(length < 0 ? 0 : length >>> 0); var index = -1,
length = collection.length,
result = Array(length);
while (++index < length) {
var value = collection[index],
rand = baseRandom(0, index);
baseEach(collection, function(value) {
var rand = baseRandom(0, ++index);
result[index] = result[rand]; result[index] = result[rand];
result[rand] = value; result[rand] = value;
}); }
return result; return result;
} }
/** /**
* Gets the size of the collection by returning `collection.length` for arrays * Gets the size of the collection by returning `collection.length` for
* and array-like objects or the number of own enumerable properties for objects. * array-like values or the number of own enumerable properties for objects.
* *
* @static * @static
* @memberOf _ * @memberOf _
@@ -5310,14 +5324,8 @@
* // => [2, 3, 4] * // => [2, 3, 4]
*/ */
function toArray(collection) { function toArray(collection) {
var length = collection ? collection.length : 0; var iterable = toIterable(collection);
return iterable === collection ? slice(collection) : iterable;
if (typeof length == 'number' && length > -1 && length <= maxSafeInteger) {
return (support.unindexedChars && isString(collection))
? collection.split('')
: slice(collection);
}
return values(collection);
} }
/** /**
@@ -5449,7 +5457,8 @@
function bindAll(object) { function bindAll(object) {
return baseBindAll(object, arguments.length > 1 return baseBindAll(object, arguments.length > 1
? baseFlatten(arguments, false, false, 1) ? baseFlatten(arguments, false, false, 1)
: functions(object)); : functions(object)
);
} }
/** /**
@@ -6731,8 +6740,8 @@
/** /**
* Checks if a collection is empty. A value is considered empty unless it is * Checks if a collection is empty. A value is considered empty unless it is
* an array, array-like object, or string with a length greater than `0` or * an array-like value with a length greater than `0` or an object with own
* an object with own enumerable properties. * enumerable properties.
* *
* @static * @static
* @memberOf _ * @memberOf _
@@ -6757,9 +6766,8 @@
* // => false * // => false
*/ */
function isEmpty(value) { function isEmpty(value) {
var result = true;
if (value == null) { if (value == null) {
return result; return true;
} }
var length = value.length; var length = value.length;
if ((typeof length == 'number' && length > -1 && length <= maxSafeInteger) && if ((typeof length == 'number' && length > -1 && length <= maxSafeInteger) &&
@@ -6767,11 +6775,7 @@
(typeof value == 'object' && isFunction(value.splice)))) { (typeof value == 'object' && isFunction(value.splice)))) {
return !length; return !length;
} }
baseForOwn(value, function() { return !keys(value).length;
result = false;
return result;
});
return result;
} }
/** /**
@@ -7207,7 +7211,7 @@
while (++index < length) { while (++index < length) {
result[index] = String(index); result[index] = String(index);
} }
// Lo-Dash skips the `constructor` property when it infers it's iterating // Lo-Dash skips the `constructor` property when it infers it is iterating
// over a `prototype` object because IE < 9 can't set the `[[Enumerable]]` // over a `prototype` object because IE < 9 can't set the `[[Enumerable]]`
// attribute of an existing property and the `constructor` property of a // attribute of an existing property and the `constructor` property of a
// prototype defaults to non-enumerable. // prototype defaults to non-enumerable.
@@ -7434,7 +7438,8 @@
} }
return basePick(Object(object), typeof predicate == 'function' return basePick(Object(object), typeof predicate == 'function'
? lodash.callback(predicate, thisArg, 3) ? lodash.callback(predicate, thisArg, 3)
: baseFlatten(arguments, false, false, 1)); : baseFlatten(arguments, false, false, 1)
);
} }
/** /**
@@ -7470,6 +7475,7 @@
*/ */
function transform(object, iterator, accumulator, thisArg) { function transform(object, iterator, accumulator, thisArg) {
var isArr = isArrayLike(object); var isArr = isArrayLike(object);
if (accumulator == null) { if (accumulator == null) {
if (isArr) { if (isArr) {
accumulator = []; accumulator = [];