@@ -24,11 +24,15 @@ var push = ArrayProto.push,
2424 toString = ObjProto . toString ,
2525 hasOwnProperty = ObjProto . hasOwnProperty ;
2626
27- // All **ECMAScript 5** native function implementations that we hope to use
27+ // Modern feature detection.
28+ var supportsArrayBuffer = typeof ArrayBuffer !== 'undefined' ;
29+
30+ // All **ECMAScript 5+** native function implementations that we hope to use
2831// are declared here.
2932var nativeIsArray = Array . isArray ,
3033 nativeKeys = Object . keys ,
31- nativeCreate = Object . create ;
34+ nativeCreate = Object . create ,
35+ nativeIsView = supportsArrayBuffer && ArrayBuffer . isView ;
3236
3337// Create references to these builtin functions because we override them.
3438var _isNaN = root . isNaN ,
@@ -152,16 +156,26 @@ function deepGet(obj, path) {
152156 return length ? obj : void 0 ;
153157}
154158
159+ // Common logic for isArrayLike and isBufferLike.
160+ var MAX_ARRAY_INDEX = Math . pow ( 2 , 53 ) - 1 ;
161+ function createSizePropertyCheck ( getSizeProperty ) {
162+ return function ( collection ) {
163+ var sizeProperty = getSizeProperty ( collection ) ;
164+ return typeof sizeProperty == 'number' && sizeProperty >= 0 && sizeProperty <= MAX_ARRAY_INDEX ;
165+ }
166+ }
167+
155168// Helper for collection methods to determine whether a collection
156169// should be iterated as an array or as an object.
157170// Related: https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
158171// Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
159- var MAX_ARRAY_INDEX = Math . pow ( 2 , 53 ) - 1 ;
160172var getLength = shallowProperty ( 'length' ) ;
161- function isArrayLike ( collection ) {
162- var length = getLength ( collection ) ;
163- return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX ;
164- }
173+ var isArrayLike = createSizePropertyCheck ( getLength ) ;
174+
175+ // Likewise to determine whether we should spend extensive checks against
176+ // `ArrayBuffer` et al.
177+ var getByteLength = shallowProperty ( 'byteLength' ) ;
178+ var isBufferLike = createSizePropertyCheck ( getByteLength ) ;
165179
166180// Collection Functions
167181// --------------------
@@ -1206,10 +1220,11 @@ function deepEq(a, b, aStack, bStack) {
12061220 // Compare `[[Class]]` names.
12071221 var className = toString . call ( a ) ;
12081222 if ( className !== toString . call ( b ) ) return false ;
1223+
12091224 switch ( className ) {
1210- // Strings, numbers, regular expressions, dates, and booleans are compared by value.
1225+ // These types are compared by value.
12111226 case '[object RegExp]' :
1212- // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
1227+ // RegExps are coerced to strings for comparison (Note: '' + /a/i === '/a/i')
12131228 case '[object String]' :
12141229 // Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
12151230 // equivalent to `new String("5")`.
@@ -1228,6 +1243,25 @@ function deepEq(a, b, aStack, bStack) {
12281243 return + a === + b ;
12291244 case '[object Symbol]' :
12301245 return SymbolProto . valueOf . call ( a ) === SymbolProto . valueOf . call ( b ) ;
1246+ case '[object ArrayBuffer]' :
1247+ // Coerce to `DataView` so we can fall through to the next case.
1248+ return deepEq ( new DataView ( a ) , new DataView ( b ) , aStack , bStack ) ;
1249+ case '[object DataView]' :
1250+ var byteLength = getByteLength ( a ) ;
1251+ if ( byteLength !== getByteLength ( b ) ) {
1252+ return false ;
1253+ }
1254+ while ( byteLength -- ) {
1255+ if ( a . getUint8 ( byteLength ) !== b . getUint8 ( byteLength ) ) {
1256+ return false ;
1257+ }
1258+ }
1259+ return true ;
1260+ }
1261+
1262+ if ( isTypedArray ( a ) ) {
1263+ // Coerce typed arrays to `DataView`.
1264+ return deepEq ( new DataView ( a . buffer ) , new DataView ( b . buffer ) , aStack , bStack ) ;
12311265 }
12321266
12331267 var areArrays = className === '[object Array]' ;
@@ -1325,7 +1359,7 @@ export function isObject(obj) {
13251359 return type === 'function' || type === 'object' && ! ! obj ;
13261360}
13271361
1328- // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError, isMap, isWeakMap, isSet, isWeakSet .
1362+ // Add some isType methods.
13291363export var isArguments = tagTester ( 'Arguments' ) ;
13301364export var isFunction = tagTester ( 'Function' ) ;
13311365export var isString = tagTester ( 'String' ) ;
@@ -1338,6 +1372,8 @@ export var isMap = tagTester('Map');
13381372export var isWeakMap = tagTester ( 'WeakMap' ) ;
13391373export var isSet = tagTester ( 'Set' ) ;
13401374export var isWeakSet = tagTester ( 'WeakSet' ) ;
1375+ export var isArrayBuffer = tagTester ( 'ArrayBuffer' ) ;
1376+ export var isDataView = tagTester ( 'DataView' ) ;
13411377
13421378// Define a fallback version of the method in browsers (ahem, IE < 9), where
13431379// there isn't any inspectable "Arguments" type.
@@ -1383,6 +1419,14 @@ export function isUndefined(obj) {
13831419 return obj === void 0 ;
13841420}
13851421
1422+ // Is a given value a typed array?
1423+ var typedArrayPattern = / \[ o b j e c t ( ( I | U i ) n t ( 8 | 1 6 | 3 2 ) | F l o a t ( 3 2 | 6 4 ) | U i n t 8 C l a m p e d | B i g ( I | U i ) n t 6 4 ) A r r a y \] / ;
1424+ export var isTypedArray = supportsArrayBuffer ? function ( obj ) {
1425+ // `ArrayBuffer.isView` is the most future-proof, so use it when available.
1426+ // Otherwise, fall back on the above regular expression.
1427+ return nativeIsView ? ( nativeIsView ( obj ) && ! isDataView ( obj ) ) : isBufferLike ( obj ) && typedArrayPattern . test ( toString . call ( obj ) ) ;
1428+ } : constant ( false ) ;
1429+
13861430// Shortcut function for checking if an object has a given property directly
13871431// on itself (in other words, not on a prototype).
13881432export function has ( obj , path ) {
0 commit comments