diff --git a/README.md b/README.md index bd1939f99..e903685e9 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# lodash-amd v4.16.3 +# lodash-amd v4.16.4 The [Lodash](https://lodash.com/) library exported as [AMD](https://github.com/amdjs/amdjs-api/wiki/AMD) modules. @@ -27,4 +27,4 @@ require({ }); ``` -See the [package source](https://github.com/lodash/lodash/tree/4.16.3-amd) for more details. +See the [package source](https://github.com/lodash/lodash/tree/4.16.4-amd) for more details. diff --git a/_arrayLikeKeys.js b/_arrayLikeKeys.js index 27913ca2b..0fd715e5f 100644 --- a/_arrayLikeKeys.js +++ b/_arrayLikeKeys.js @@ -1,4 +1,4 @@ -define(['./_baseTimes', './isArguments', './isArray', './_isIndex'], function(baseTimes, isArguments, isArray, isIndex) { +define(['./_baseTimes', './isArguments', './isArray', './isBuffer', './_isIndex', './isTypedArray'], function(baseTimes, isArguments, isArray, isBuffer, isIndex, isTypedArray) { /** Used for built-in method references. */ var objectProto = Object.prototype; @@ -15,18 +15,26 @@ define(['./_baseTimes', './isArguments', './isArray', './_isIndex'], function(ba * @returns {Array} Returns the array of property names. */ function arrayLikeKeys(value, inherited) { - // Safari 8.1 makes `arguments.callee` enumerable in strict mode. - // Safari 9 makes `arguments.length` enumerable in strict mode. - var result = (isArray(value) || isArguments(value)) - ? baseTimes(value.length, String) - : []; - - var length = result.length, - skipIndexes = !!length; + var isArr = isArray(value), + isArg = !isArr && isArguments(value), + isBuff = !isArr && !isArg && isBuffer(value), + isType = !isArr && !isArg && !isBuff && isTypedArray(value), + skipIndexes = isArr || isArg || isBuff || isType, + result = skipIndexes ? baseTimes(value.length, String) : [], + length = result.length; for (var key in value) { if ((inherited || hasOwnProperty.call(value, key)) && - !(skipIndexes && (key == 'length' || isIndex(key, length)))) { + !(skipIndexes && ( + // Safari 9 has enumerable `arguments.length` in strict mode. + key == 'length' || + // Node.js 0.10 has enumerable non-index properties on buffers. + (isBuff && (key == 'offset' || key == 'parent')) || + // PhantomJS 2 has enumerable non-index properties on typed arrays. + (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) || + // Skip index properties. + isIndex(key, length) + ))) { result.push(key); } } diff --git a/_arraySampleSize.js b/_arraySampleSize.js index 6369db847..c9f62ebb4 100644 --- a/_arraySampleSize.js +++ b/_arraySampleSize.js @@ -1,4 +1,4 @@ -define(['./_copyArray', './_shuffleSelf'], function(copyArray, shuffleSelf) { +define(['./_baseClamp', './_copyArray', './_shuffleSelf'], function(baseClamp, copyArray, shuffleSelf) { /** * A specialized version of `_.sampleSize` for arrays. @@ -9,7 +9,7 @@ define(['./_copyArray', './_shuffleSelf'], function(copyArray, shuffleSelf) { * @returns {Array} Returns the random elements. */ function arraySampleSize(array, n) { - return shuffleSelf(copyArray(array), n); + return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length)); } return arraySampleSize; diff --git a/_baseClone.js b/_baseClone.js index e1ceb4989..e1cc0c3b1 100644 --- a/_baseClone.js +++ b/_baseClone.js @@ -106,9 +106,7 @@ define(['./_Stack', './_arrayEach', './_assignValue', './_baseAssign', './_clone } stack.set(value, result); - if (!isArr) { - var props = isFull ? getAllKeys(value) : keys(value); - } + var props = isArr ? undefined : (isFull ? getAllKeys : keys)(value); arrayEach(props || value, function(subValue, key) { if (props) { key = subValue; diff --git a/_baseIsArguments.js b/_baseIsArguments.js new file mode 100644 index 000000000..8297e3726 --- /dev/null +++ b/_baseIsArguments.js @@ -0,0 +1,28 @@ +define(['./isObjectLike'], function(isObjectLike) { + + /** `Object#toString` result references. */ + var argsTag = '[object Arguments]'; + + /** Used for built-in method references. */ + var objectProto = Object.prototype; + + /** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ + var objectToString = objectProto.toString; + + /** + * The base implementation of `_.isArguments`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + */ + function baseIsArguments(value) { + return isObjectLike(value) && objectToString.call(value) == argsTag; + } + + return baseIsArguments; +}); diff --git a/_baseMerge.js b/_baseMerge.js index e7b16a4c1..3f07daedd 100644 --- a/_baseMerge.js +++ b/_baseMerge.js @@ -1,4 +1,4 @@ -define(['./_Stack', './_arrayEach', './_assignMergeValue', './_baseKeysIn', './_baseMergeDeep', './isArray', './isObject', './isTypedArray'], function(Stack, arrayEach, assignMergeValue, baseKeysIn, baseMergeDeep, isArray, isObject, isTypedArray) { +define(['./_Stack', './_assignMergeValue', './_baseFor', './_baseMergeDeep', './isObject', './keysIn'], function(Stack, assignMergeValue, baseFor, baseMergeDeep, isObject, keysIn) { /** Used as a safe reference for `undefined` in pre-ES5 environments. */ var undefined; @@ -18,14 +18,7 @@ define(['./_Stack', './_arrayEach', './_assignMergeValue', './_baseKeysIn', './_ if (object === source) { return; } - if (!(isArray(source) || isTypedArray(source))) { - var props = baseKeysIn(source); - } - arrayEach(props || source, function(srcValue, key) { - if (props) { - key = srcValue; - srcValue = source[key]; - } + baseFor(source, function(srcValue, key) { if (isObject(srcValue)) { stack || (stack = new Stack); baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack); @@ -40,7 +33,7 @@ define(['./_Stack', './_arrayEach', './_assignMergeValue', './_baseKeysIn', './_ } assignMergeValue(object, key, newValue); } - }); + }, keysIn); } return baseMerge; diff --git a/_baseMergeDeep.js b/_baseMergeDeep.js index 4066c9860..c8b635af8 100644 --- a/_baseMergeDeep.js +++ b/_baseMergeDeep.js @@ -1,4 +1,4 @@ -define(['./_assignMergeValue', './_cloneTypedArray', './_copyArray', './_initCloneObject', './isArguments', './isArray', './isArrayLikeObject', './isFunction', './isObject', './isPlainObject', './isTypedArray', './toPlainObject'], function(assignMergeValue, cloneTypedArray, copyArray, initCloneObject, isArguments, isArray, isArrayLikeObject, isFunction, isObject, isPlainObject, isTypedArray, toPlainObject) { +define(['./_assignMergeValue', './_cloneBuffer', './_cloneTypedArray', './_copyArray', './_initCloneObject', './isArguments', './isArray', './isArrayLikeObject', './isBuffer', './isFunction', './isObject', './isPlainObject', './isTypedArray', './toPlainObject'], function(assignMergeValue, cloneBuffer, cloneTypedArray, copyArray, initCloneObject, isArguments, isArray, isArrayLikeObject, isBuffer, isFunction, isObject, isPlainObject, isTypedArray, toPlainObject) { /** Used as a safe reference for `undefined` in pre-ES5 environments. */ var undefined; @@ -35,16 +35,21 @@ define(['./_assignMergeValue', './_cloneTypedArray', './_copyArray', './_initClo if (isCommon) { var isArr = isArray(srcValue), - isTyped = !isArr && isTypedArray(srcValue); + isBuff = !isArr && isBuffer(srcValue), + isTyped = !isArr && !isBuff && isTypedArray(srcValue); newValue = srcValue; - if (isArr || isTyped) { + if (isArr || isBuff || isTyped) { if (isArray(objValue)) { newValue = objValue; } else if (isArrayLikeObject(objValue)) { newValue = copyArray(objValue); } + else if (isBuff) { + isCommon = false; + newValue = cloneBuffer(srcValue, true); + } else if (isTyped) { isCommon = false; newValue = cloneTypedArray(srcValue, true); diff --git a/_baseSampleSize.js b/_baseSampleSize.js index a42907674..b760f36af 100644 --- a/_baseSampleSize.js +++ b/_baseSampleSize.js @@ -1,4 +1,4 @@ -define(['./_shuffleSelf', './values'], function(shuffleSelf, values) { +define(['./_baseClamp', './_shuffleSelf', './values'], function(baseClamp, shuffleSelf, values) { /** * The base implementation of `_.sampleSize` without param guards. @@ -9,7 +9,8 @@ define(['./_shuffleSelf', './values'], function(shuffleSelf, values) { * @returns {Array} Returns the random elements. */ function baseSampleSize(collection, n) { - return shuffleSelf(values(collection), n); + var array = values(collection); + return shuffleSelf(array, baseClamp(n, 0, array.length)); } return baseSampleSize; diff --git a/_baseToString.js b/_baseToString.js index f075901cb..a96dce168 100644 --- a/_baseToString.js +++ b/_baseToString.js @@ -1,4 +1,4 @@ -define(['./_Symbol', './isSymbol'], function(Symbol, isSymbol) { +define(['./_Symbol', './_arrayMap', './isArray', './isSymbol'], function(Symbol, arrayMap, isArray, isSymbol) { /** Used as a safe reference for `undefined` in pre-ES5 environments. */ var undefined; @@ -23,6 +23,10 @@ define(['./_Symbol', './isSymbol'], function(Symbol, isSymbol) { if (typeof value == 'string') { return value; } + if (isArray(value)) { + // Recursively convert values (susceptible to call stack limits). + return arrayMap(value, baseToString) + ''; + } if (isSymbol(value)) { return symbolToString ? symbolToString.call(value) : ''; } diff --git a/_shuffleSelf.js b/_shuffleSelf.js index bc9eee0a2..04d3fdbd8 100644 --- a/_shuffleSelf.js +++ b/_shuffleSelf.js @@ -1,4 +1,4 @@ -define(['./_baseClamp', './_baseRandom'], function(baseClamp, baseRandom) { +define(['./_baseRandom'], function(baseRandom) { /** Used as a safe reference for `undefined` in pre-ES5 environments. */ var undefined; @@ -16,7 +16,7 @@ define(['./_baseClamp', './_baseRandom'], function(baseClamp, baseRandom) { length = array.length, lastIndex = length - 1; - size = size === undefined ? length : baseClamp(size, 0, length); + size = size === undefined ? length : size; while (++index < size) { var rand = baseRandom(index, lastIndex), value = array[rand]; diff --git a/isArguments.js b/isArguments.js index be51856c2..ff60e3544 100644 --- a/isArguments.js +++ b/isArguments.js @@ -1,7 +1,4 @@ -define(['./isArrayLikeObject'], function(isArrayLikeObject) { - - /** `Object#toString` result references. */ - var argsTag = '[object Arguments]'; +define(['./_baseIsArguments', './isObjectLike'], function(baseIsArguments, isObjectLike) { /** Used for built-in method references. */ var objectProto = Object.prototype; @@ -9,13 +6,6 @@ define(['./isArrayLikeObject'], function(isArrayLikeObject) { /** Used to check objects for own properties. */ var hasOwnProperty = objectProto.hasOwnProperty; - /** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) - * of values. - */ - var objectToString = objectProto.toString; - /** Built-in value references. */ var propertyIsEnumerable = objectProto.propertyIsEnumerable; @@ -37,11 +27,10 @@ define(['./isArrayLikeObject'], function(isArrayLikeObject) { * _.isArguments([1, 2, 3]); * // => false */ - function isArguments(value) { - // Safari 8.1 makes `arguments.callee` enumerable in strict mode. - return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') && - (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag); - } + var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { + return isObjectLike(value) && hasOwnProperty.call(value, 'callee') && + !propertyIsEnumerable.call(value, 'callee'); + }; return isArguments; }); diff --git a/isEmpty.js b/isEmpty.js index a8d3c8260..bdcf5493b 100644 --- a/isEmpty.js +++ b/isEmpty.js @@ -1,4 +1,4 @@ -define(['./_getTag', './isArguments', './isArray', './isArrayLike', './isBuffer', './_isPrototype', './_nativeKeys'], function(getTag, isArguments, isArray, isArrayLike, isBuffer, isPrototype, nativeKeys) { +define(['./_baseKeys', './_getTag', './isArguments', './isArray', './isArrayLike', './isBuffer', './_isPrototype', './isTypedArray'], function(baseKeys, getTag, isArguments, isArray, isArrayLike, isBuffer, isPrototype, isTypedArray) { /** `Object#toString` result references. */ var mapTag = '[object Map]', @@ -45,8 +45,8 @@ define(['./_getTag', './isArguments', './isArray', './isArrayLike', './isBuffer' */ function isEmpty(value) { if (isArrayLike(value) && - (isArray(value) || typeof value == 'string' || - typeof value.splice == 'function' || isBuffer(value) || isArguments(value))) { + (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' || + isBuffer(value) || isTypedArray(value) || isArguments(value))) { return !value.length; } var tag = getTag(value); @@ -54,7 +54,7 @@ define(['./_getTag', './isArguments', './isArray', './isArrayLike', './isBuffer' return !value.size; } if (isPrototype(value)) { - return !nativeKeys(value).length; + return !baseKeys(value).length; } for (var key in value) { if (hasOwnProperty.call(value, key)) { diff --git a/isFunction.js b/isFunction.js index b8aa55d00..468b1ab2b 100644 --- a/isFunction.js +++ b/isFunction.js @@ -34,7 +34,7 @@ define(['./isObject'], function(isObject) { */ function isFunction(value) { // The use of `Object#toString` avoids issues with the `typeof` operator - // in Safari 8-9 which returns 'object' for typed array and other constructors. + // in Safari 9 which returns 'object' for typed array and other constructors. var tag = isObject(value) ? objectToString.call(value) : ''; return tag == funcTag || tag == genTag || tag == proxyTag; } diff --git a/main.js b/main.js index 86eaaa365..f00108ba4 100644 --- a/main.js +++ b/main.js @@ -13,7 +13,7 @@ var undefined; /** Used as the semantic version number. */ - var VERSION = '4.16.3'; + var VERSION = '4.16.4'; /** Used as the size to enable large array optimizations. */ var LARGE_ARRAY_SIZE = 200; @@ -2388,18 +2388,26 @@ * @returns {Array} Returns the array of property names. */ function arrayLikeKeys(value, inherited) { - // Safari 8.1 makes `arguments.callee` enumerable in strict mode. - // Safari 9 makes `arguments.length` enumerable in strict mode. - var result = (isArray(value) || isArguments(value)) - ? baseTimes(value.length, String) - : []; - - var length = result.length, - skipIndexes = !!length; + var isArr = isArray(value), + isArg = !isArr && isArguments(value), + isBuff = !isArr && !isArg && isBuffer(value), + isType = !isArr && !isArg && !isBuff && isTypedArray(value), + skipIndexes = isArr || isArg || isBuff || isType, + result = skipIndexes ? baseTimes(value.length, String) : [], + length = result.length; for (var key in value) { if ((inherited || hasOwnProperty.call(value, key)) && - !(skipIndexes && (key == 'length' || isIndex(key, length)))) { + !(skipIndexes && ( + // Safari 9 has enumerable `arguments.length` in strict mode. + key == 'length' || + // Node.js 0.10 has enumerable non-index properties on buffers. + (isBuff && (key == 'offset' || key == 'parent')) || + // PhantomJS 2 has enumerable non-index properties on typed arrays. + (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) || + // Skip index properties. + isIndex(key, length) + ))) { result.push(key); } } @@ -2427,7 +2435,7 @@ * @returns {Array} Returns the random elements. */ function arraySampleSize(array, n) { - return shuffleSelf(copyArray(array), n); + return shuffleSelf(copyArray(array), baseClamp(n, 0, array.length)); } /** @@ -2663,9 +2671,7 @@ } stack.set(value, result); - if (!isArr) { - var props = isFull ? getAllKeys(value) : keys(value); - } + var props = isArr ? undefined : (isFull ? getAllKeys : keys)(value); arrayEach(props || value, function(subValue, key) { if (props) { key = subValue; @@ -3199,6 +3205,17 @@ return func == null ? undefined : apply(func, object, args); } + /** + * The base implementation of `_.isArguments`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + */ + function baseIsArguments(value) { + return isObjectLike(value) && objectToString.call(value) == argsTag; + } + /** * The base implementation of `_.isArrayBuffer` without Node.js optimizations. * @@ -3575,14 +3592,7 @@ if (object === source) { return; } - if (!(isArray(source) || isTypedArray(source))) { - var props = baseKeysIn(source); - } - arrayEach(props || source, function(srcValue, key) { - if (props) { - key = srcValue; - srcValue = source[key]; - } + baseFor(source, function(srcValue, key) { if (isObject(srcValue)) { stack || (stack = new Stack); baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack); @@ -3597,7 +3607,7 @@ } assignMergeValue(object, key, newValue); } - }); + }, keysIn); } /** @@ -3632,16 +3642,21 @@ if (isCommon) { var isArr = isArray(srcValue), - isTyped = !isArr && isTypedArray(srcValue); + isBuff = !isArr && isBuffer(srcValue), + isTyped = !isArr && !isBuff && isTypedArray(srcValue); newValue = srcValue; - if (isArr || isTyped) { + if (isArr || isBuff || isTyped) { if (isArray(objValue)) { newValue = objValue; } else if (isArrayLikeObject(objValue)) { newValue = copyArray(objValue); } + else if (isBuff) { + isCommon = false; + newValue = cloneBuffer(srcValue, true); + } else if (isTyped) { isCommon = false; newValue = cloneTypedArray(srcValue, true); @@ -3938,7 +3953,8 @@ * @returns {Array} Returns the random elements. */ function baseSampleSize(collection, n) { - return shuffleSelf(values(collection), n); + var array = values(collection); + return shuffleSelf(array, baseClamp(n, 0, array.length)); } /** @@ -4215,6 +4231,10 @@ if (typeof value == 'string') { return value; } + if (isArray(value)) { + // Recursively convert values (susceptible to call stack limits). + return arrayMap(value, baseToString) + ''; + } if (isSymbol(value)) { return symbolToString ? symbolToString.call(value) : ''; } @@ -6610,7 +6630,7 @@ length = array.length, lastIndex = length - 1; - size = size === undefined ? length : baseClamp(size, 0, length); + size = size === undefined ? length : size; while (++index < size) { var rand = baseRandom(index, lastIndex), value = array[rand]; @@ -11183,11 +11203,10 @@ * _.isArguments([1, 2, 3]); * // => false */ - function isArguments(value) { - // Safari 8.1 makes `arguments.callee` enumerable in strict mode. - return isArrayLikeObject(value) && hasOwnProperty.call(value, 'callee') && - (!propertyIsEnumerable.call(value, 'callee') || objectToString.call(value) == argsTag); - } + var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { + return isObjectLike(value) && hasOwnProperty.call(value, 'callee') && + !propertyIsEnumerable.call(value, 'callee'); + }; /** * Checks if `value` is classified as an `Array` object. @@ -11407,8 +11426,8 @@ */ function isEmpty(value) { if (isArrayLike(value) && - (isArray(value) || typeof value == 'string' || - typeof value.splice == 'function' || isBuffer(value) || isArguments(value))) { + (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' || + isBuffer(value) || isTypedArray(value) || isArguments(value))) { return !value.length; } var tag = getTag(value); @@ -11416,7 +11435,7 @@ return !value.size; } if (isPrototype(value)) { - return !nativeKeys(value).length; + return !baseKeys(value).length; } for (var key in value) { if (hasOwnProperty.call(value, key)) { @@ -11571,7 +11590,7 @@ */ function isFunction(value) { // The use of `Object#toString` avoids issues with the `typeof` operator - // in Safari 8-9 which returns 'object' for typed array and other constructors. + // in Safari 9 which returns 'object' for typed array and other constructors. var tag = isObject(value) ? objectToString.call(value) : ''; return tag == funcTag || tag == genTag || tag == proxyTag; } @@ -12461,8 +12480,8 @@ * @memberOf _ * @since 4.0.0 * @category Lang - * @param {*} value The value to process. - * @returns {string} Returns the string. + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. * @example * * _.toString(null); @@ -13646,22 +13665,23 @@ * // => { '1': ['a', 'c'], '2': ['b'] } */ function transform(object, iteratee, accumulator) { - var isArr = isArray(object) || isTypedArray(object); - iteratee = getIteratee(iteratee, 4); + var isArr = isArray(object), + isArrLike = isArr || isBuffer(object) || isTypedArray(object); + iteratee = getIteratee(iteratee, 4); if (accumulator == null) { - if (isArr || isObject(object)) { - var Ctor = object.constructor; - if (isArr) { - accumulator = isArray(object) ? new Ctor : []; - } else { - accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {}; - } - } else { + var Ctor = object && object.constructor; + if (isArrLike) { + accumulator = isArr ? new Ctor : []; + } + else if (isObject(object)) { + accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {}; + } + else { accumulator = {}; } } - (isArr ? arrayEach : baseForOwn)(object, function(value, index, object) { + (isArrLike ? arrayEach : baseForOwn)(object, function(value, index, object) { return iteratee(accumulator, value, index, object); }); return accumulator; diff --git a/package.json b/package.json index 1fcb449ae..b4438d9dd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lodash-amd", - "version": "4.16.3", + "version": "4.16.4", "description": "Lodash exported as AMD modules.", "keywords": "amd, modules, stdlib, util", "homepage": "https://lodash.com/custom-builds", diff --git a/toString.js b/toString.js index ab181a95c..a071c4008 100644 --- a/toString.js +++ b/toString.js @@ -8,8 +8,8 @@ define(['./_baseToString'], function(baseToString) { * @memberOf _ * @since 4.0.0 * @category Lang - * @param {*} value The value to process. - * @returns {string} Returns the string. + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. * @example * * _.toString(null); diff --git a/transform.js b/transform.js index 51cc194c0..8f847a3bc 100644 --- a/transform.js +++ b/transform.js @@ -1,4 +1,4 @@ -define(['./_arrayEach', './_baseCreate', './_baseForOwn', './_baseIteratee', './_getPrototype', './isArray', './isFunction', './isObject', './isTypedArray'], function(arrayEach, baseCreate, baseForOwn, baseIteratee, getPrototype, isArray, isFunction, isObject, isTypedArray) { +define(['./_arrayEach', './_baseCreate', './_baseForOwn', './_baseIteratee', './_getPrototype', './isArray', './isBuffer', './isFunction', './isObject', './isTypedArray'], function(arrayEach, baseCreate, baseForOwn, baseIteratee, getPrototype, isArray, isBuffer, isFunction, isObject, isTypedArray) { /** * An alternative to `_.reduce`; this method transforms `object` to a new @@ -31,22 +31,23 @@ define(['./_arrayEach', './_baseCreate', './_baseForOwn', './_baseIteratee', './ * // => { '1': ['a', 'c'], '2': ['b'] } */ function transform(object, iteratee, accumulator) { - var isArr = isArray(object) || isTypedArray(object); - iteratee = baseIteratee(iteratee, 4); + var isArr = isArray(object), + isArrLike = isArr || isBuffer(object) || isTypedArray(object); + iteratee = baseIteratee(iteratee, 4); if (accumulator == null) { - if (isArr || isObject(object)) { - var Ctor = object.constructor; - if (isArr) { - accumulator = isArray(object) ? new Ctor : []; - } else { - accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {}; - } - } else { + var Ctor = object && object.constructor; + if (isArrLike) { + accumulator = isArr ? new Ctor : []; + } + else if (isObject(object)) { + accumulator = isFunction(Ctor) ? baseCreate(getPrototype(object)) : {}; + } + else { accumulator = {}; } } - (isArr ? arrayEach : baseForOwn)(object, function(value, index, object) { + (isArrLike ? arrayEach : baseForOwn)(object, function(value, index, object) { return iteratee(accumulator, value, index, object); }); return accumulator;