From 34cde430a580672acf3b298eded923e9e8933de2 Mon Sep 17 00:00:00 2001 From: John-David Dalton Date: Sun, 25 May 2014 12:24:32 -0700 Subject: [PATCH] Add private `isArrayLike` helper and add object classifications for typed arrays with support for cloning and comparing them. --- lodash.js | 74 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 8 deletions(-) diff --git a/lodash.js b/lodash.js index ffb21365f..d6e9f3f76 100644 --- a/lodash.js +++ b/lodash.js @@ -121,18 +121,53 @@ dateClass = '[object Date]', errorClass = '[object Error]', funcClass = '[object Function]', + mapClass = '[object Map]', numberClass = '[object Number]', objectClass = '[object Object]', regexpClass = '[object RegExp]', - stringClass = '[object String]'; + setClass = '[object Set]', + stringClass = '[object String]', + weakMapClass = '[object WeakMap]'; + + var arrayBufferClass = '[object ArrayBuffer]', + f32Class = '[object Float32Array]', + f64Class = '[object Float64Array]', + i8Class = '[object Int8Array]', + i16Class = '[object Int16Array]', + i32Class = '[object Int32Array]', + u8Class = '[object Uint8Array]', + u8cClass = '[object Uint8ClampedArray]', + u16Class = '[object Uint16Array]', + u32Class = '[object Uint32Array]'; /** Used to identify object classifications that `_.clone` supports */ var cloneableClasses = {}; - cloneableClasses[funcClass] = false; cloneableClasses[argsClass] = cloneableClasses[arrayClass] = - cloneableClasses[boolClass] = cloneableClasses[dateClass] = + cloneableClasses[arrayBufferClass] = cloneableClasses[boolClass] = + cloneableClasses[dateClass] = cloneableClasses[errorClass] = + cloneableClasses[f64Class] = cloneableClasses[i8Class] = + cloneableClasses[i16Class] = cloneableClasses[i32Class] = cloneableClasses[numberClass] = cloneableClasses[objectClass] = - cloneableClasses[regexpClass] = cloneableClasses[stringClass] = true; + cloneableClasses[regexpClass] = cloneableClasses[stringClass] = + cloneableClasses[u8Class] = cloneableClasses[u8cClass] = + cloneableClasses[u16Class] = cloneableClasses[u32Class] = true; + cloneableClasses[funcClass] = cloneableClasses[mapClass] = + cloneableClasses[setClass] = cloneableClasses[weakMapClass] = false; + + /** Used to identify object classifications that are treated like arrays */ + var arrayLikeClasses = {}; + arrayLikeClasses[argsClass] = + arrayLikeClasses[arrayClass] = arrayLikeClasses[f32Class] = + arrayLikeClasses[f64Class] = arrayLikeClasses[i8Class] = + arrayLikeClasses[i16Class] = arrayLikeClasses[i32Class] = + arrayLikeClasses[u8Class] = arrayLikeClasses[u8cClass] = + arrayLikeClasses[u16Class] = arrayLikeClasses[u32Class] = true; + arrayLikeClasses[arrayBufferClass] = arrayLikeClasses[boolClass] = + arrayLikeClasses[dateClass] = arrayLikeClasses[errorClass] = + arrayLikeClasses[funcClass] = arrayLikeClasses[mapClass] = + arrayLikeClasses[numberClass] = arrayLikeClasses[objectClass] = + arrayLikeClasses[regexpClass] = arrayLikeClasses[setClass] = + arrayLikeClasses[stringClass] = arrayLikeClasses[weakMapClass] = false; /** Used as an internal `_.debounce` options object by `_.throttle` */ var debounceOptions = { @@ -1197,10 +1232,21 @@ } var ctor = ctorByClass[className]; switch (className) { + case arrayBufferClass: + return value.slice(); + case boolClass: case dateClass: return new ctor(+value); + case errorClass: + return new ctor(value.message); + + case f32Class: case f64Class: + case i8Class: case i16Class: case i32Class: + case u8Class: case u8cClass: case u16Class: case u32Class: + return value.subarray(0); + case numberClass: case stringClass: return new ctor(value); @@ -1754,7 +1800,7 @@ // treat string primitives and their corresponding object instances as equal return value == String(other); } - var isArr = valClass == arrayClass; + var isArr = arrayLikeClasses[valClass]; if (!isArr) { // exit for functions and DOM nodes if (valClass != objectClass || (!support.nodeClass && (isNode(value) || isNode(other)))) { @@ -1923,8 +1969,8 @@ if (!object) { return object; } - (isArray(source) ? arrayEach : baseForOwn)(source, function(srcValue, key, source) { - var isArr = srcValue && isArray(srcValue), + (isArrayLike(source) ? arrayEach : baseForOwn)(source, function(srcValue, key, source) { + var isArr = srcValue && isArrayLike(srcValue), isObj = srcValue && isPlainObject(srcValue), value = object[key]; @@ -2462,6 +2508,18 @@ return result === indexOf ? baseIndexOf : result; } + /** + * Checks if `value` is an array-like object. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array-like object, else `false`. + */ + function isArrayLike(value) { + return (value && typeof value == 'object' && typeof value.length == 'number' && + arrayLikeClasses[toString.call(value)]) || false; + } + /** * Checks if `value` is a native function. * @@ -7198,7 +7256,7 @@ * // => { 'a': 3, 'b': 6, 'c': 9 } */ function transform(object, callback, accumulator, thisArg) { - var isArr = isArray(object); + var isArr = isArrayLike(object); if (accumulator == null) { if (isArr) { accumulator = [];