Today we will figure out the following: what is the Array.isArray () method, how it works under the hood, what has changed with it after ES6 was released, why it returns true for Array.prototype, and many more topics related to this method.
The isArray()
constructor method has Array
been added since version 5 of the ECMAScript standard . On the page describing this method on the MDN website it says:
The Array.isArray () method returns true if the object is an array and false if it is not an array.
Indeed, this method is well suited for testing different values to see if the value is an array. However, it has one feature (where can we go without them). If you pass this method Array.prototype
, which is an object, it returns true
. Despite the fact that:
Array.prototype instanceof Array // false
Object.getPrototypeOf(Array.prototype) === Array.prototype // false
Array.prototype.isPrototypeOf(Array.prototype) // false
Array.prototype instanceof Object // true
Object.getPrototypeOf(Array.prototype) === Object.prototype // true
Object.prototype.isPrototypeOf(Array.prototype) // true
Such unexpected behavior can confuse not only an ordinary JavaScript programmer, but also an experienced fighter. Actually, this prompted me to write this article. Someone might compare this behavior to a famous JS feature:
typeof null === 'object' // true
However, do not rush to add this case to the wtfjs list , because there is (suddenly) a logical explanation for this. But first, let's figure out why the method was created isArray()
and what is hidden under the hood.
Background
ES5 , , instanceof
.
[] instanceof Array // true
( ) prototype
( ). :
Object.getPrototypeOf([]) === Array.prototype // true
, (realm), , iframe, iframe (window). instanseof Array
false, Array Array .
, , Array. , Object.prototype.toString()
[[Class]]
. :
function isArray(obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
}
, Array.
Array.isArray Array.prototype
ES6 . Arrray.prototype
Object.prototype.toString()
[object Array]
:
Object.prototype.toString.call(Date.prototype) // [object Object]
Object.prototype.toString.call(RegExp.prototype) // [object Object]
1. false.
2. [[Class]] «Array» true.
3. false.
Object.prototype.toString()
. , [[Class]]
Array.prototype
«Array»? ?
isArray()
ES6. , , . ES6 [[Class]]
Object.prototype.toString()
-. :
…
3. O ToObject(this value).
4. isArray isArray(O).
5. isArray true, builtinTag «Array».
...
isArray()
ES6 Array.isArray()
. isArray()
, , . true
[[DefineOwnProperty]]
, ( length
).
Array.prototype
, [[DefineOwnProperty]]
. . . .
console.log(Array.prototype);
// [constructor: f, concat: f, ..., length: 0, ..., __proto__: Object]
. length
, , (__proto__
) Object
. ! .
console.log(Object.getOwnPropertyDescriptor(Array.prototype, 'length'));
// {value: 0, writable: true, enumerable: false, configurable: false}
. length
. . Array exotic object
console.log(Array.prototype.length); // 0
Array.prototype[42] = 'I\'m array';
Array.prototype[18] = 'I\'m array exotic object';
console.log(Array.prototype.length); // 43
Array.prototype.length = 20;
console.log(Array.prototype[42]); // undefined
console.log(Array.prototype[18]); // 'I\'m array exotic object'
, Array.prototype
. ( ), prototype
Array
.
Array.prototype = new Array();
Object.assign(Array.prototype, {constructor() { ... }, concat() { ... }, ...});
Object.setPrototypeOf(Array.prototype, Object.prototype);
, , Array.prototype
. , [[Class]]
( ) 'Array'
.
Function, Date, RegExp
Date
RegExp
(Object
), .. , .
Object.prototype.toString.call(Date.prototype); // [object Object]
Object.prototype.toString.call(RegExp.prototype); // [object Object]
Function.prototype
. Object.prototype.toString()
Object.prototype.toString.call(Function.prototype); // [object Function]
, Function.prototype
.
Function.prototype() // undefined;
)))
(Boolean
, Number
, String
) Object.prototype.toString
Object.prototype.toString.call(Boolean.prototype); // [object Boolean]
Object.prototype.toString.call(Number.prototype); // [object Number]
Object.prototype.toString.call(String.prototype); // [object String]
. . [[Class]]
…
3. O ToObject(this value).
…
7. , O exotic String object builtinTag «String».
…
11. , O [[BooleanData]] builtinTag «Boolean».
12. , O [[NumberData]] builtinTag «Number».
)))
String.prototype + Number.prototype + Boolean.prototype // '0false'
(String.prototype + Boolean.prototype)[Number.prototype]; // 'f'
' ' + Number.prototype + Number.prototype + '7'; // ' 007'
Symbol.toStringTag
, Object.prototype.toString()
ES6, Set
, Symbol
, Promise
, :
Object.prototype.toString.call(Map.prototype); // [object Map]
Object.prototype.toString.call(Set.prototype); // [object Set]
Object.prototype.toString.call(Promise.prototype); // [object Promise]
Object.prototype.toString.call(Symbol.prototype); // [object Symbol]
, Object.prototype.toString
, . , @@toStringTag
. Object.prototype.toString()
. , ES5 , , Set.prototype
, Promise.prototype
Set
Promise
.
, Object.prototype.toString()
.
Array.prototype
ECMAScript . , , , Array.isArray()
. , . ? - ?
- ES5 — 5- ESMAScript.
- ES6 — 6- ESMAScript.
- ECMAScript 6 | — , .
- Determining with absolute accuracy whether or not a JavaScript object is an array — , , Array.isArray .