@@ -24,11 +24,15 @@ var push = ArrayProto.push,
24
24
toString = ObjProto . toString ,
25
25
hasOwnProperty = ObjProto . hasOwnProperty ;
26
26
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
28
31
// are declared here.
29
32
var nativeIsArray = Array . isArray ,
30
33
nativeKeys = Object . keys ,
31
- nativeCreate = Object . create ;
34
+ nativeCreate = Object . create ,
35
+ nativeIsView = supportsArrayBuffer && ArrayBuffer . isView ;
32
36
33
37
// Create references to these builtin functions because we override them.
34
38
var _isNaN = root . isNaN ,
@@ -152,16 +156,26 @@ function deepGet(obj, path) {
152
156
return length ? obj : void 0 ;
153
157
}
154
158
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
+
155
168
// Helper for collection methods to determine whether a collection
156
169
// should be iterated as an array or as an object.
157
170
// Related: https://people.mozilla.org/~jorendorff/es6-draft.html#sec-tolength
158
171
// Avoids a very nasty iOS 8 JIT bug on ARM-64. #2094
159
- var MAX_ARRAY_INDEX = Math . pow ( 2 , 53 ) - 1 ;
160
172
var 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 ) ;
165
179
166
180
// Collection Functions
167
181
// --------------------
@@ -1206,10 +1220,11 @@ function deepEq(a, b, aStack, bStack) {
1206
1220
// Compare `[[Class]]` names.
1207
1221
var className = toString . call ( a ) ;
1208
1222
if ( className !== toString . call ( b ) ) return false ;
1223
+
1209
1224
switch ( className ) {
1210
- // Strings, numbers, regular expressions, dates, and booleans are compared by value.
1225
+ // These types are compared by value.
1211
1226
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')
1213
1228
case '[object String]' :
1214
1229
// Primitives and their corresponding object wrappers are equivalent; thus, `"5"` is
1215
1230
// equivalent to `new String("5")`.
@@ -1228,6 +1243,25 @@ function deepEq(a, b, aStack, bStack) {
1228
1243
return + a === + b ;
1229
1244
case '[object Symbol]' :
1230
1245
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 ) ;
1231
1265
}
1232
1266
1233
1267
var areArrays = className === '[object Array]' ;
@@ -1325,7 +1359,7 @@ export function isObject(obj) {
1325
1359
return type === 'function' || type === 'object' && ! ! obj ;
1326
1360
}
1327
1361
1328
- // Add some isType methods: isArguments, isFunction, isString, isNumber, isDate, isRegExp, isError, isMap, isWeakMap, isSet, isWeakSet .
1362
+ // Add some isType methods.
1329
1363
export var isArguments = tagTester ( 'Arguments' ) ;
1330
1364
export var isFunction = tagTester ( 'Function' ) ;
1331
1365
export var isString = tagTester ( 'String' ) ;
@@ -1338,6 +1372,8 @@ export var isMap = tagTester('Map');
1338
1372
export var isWeakMap = tagTester ( 'WeakMap' ) ;
1339
1373
export var isSet = tagTester ( 'Set' ) ;
1340
1374
export var isWeakSet = tagTester ( 'WeakSet' ) ;
1375
+ export var isArrayBuffer = tagTester ( 'ArrayBuffer' ) ;
1376
+ export var isDataView = tagTester ( 'DataView' ) ;
1341
1377
1342
1378
// Define a fallback version of the method in browsers (ahem, IE < 9), where
1343
1379
// there isn't any inspectable "Arguments" type.
@@ -1383,6 +1419,14 @@ export function isUndefined(obj) {
1383
1419
return obj === void 0 ;
1384
1420
}
1385
1421
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
+
1386
1430
// Shortcut function for checking if an object has a given property directly
1387
1431
// on itself (in other words, not on a prototype).
1388
1432
export function has ( obj , path ) {
0 commit comments