Aujourd'hui, nous allons découvrir ce qui suit: qu'est-ce que la méthode Array.isArray (), comment elle fonctionne sous le capot, ce qui a changé avec elle après la sortie d'ES6, pourquoi elle retourne true pour Array.prototype, et bien d'autres sujets liés à cette méthode.
La méthode isArray()
constructeur a Array
été ajoutée depuis la version 5 du standard ECMAScript . Sur la page décrivant cette méthode sur le site Web de MDN, il est dit:
La méthode Array.isArray () renvoie true si l'objet est un tableau et false si ce n'est pas un tableau.
En effet, cette méthode est bien adaptée pour tester différentes valeurs pour voir si la valeur est un tableau. Cependant, il a une fonctionnalité (où pouvons-nous aller sans eux). Si vous passez cette méthode Array.prototype
, qui est un objet, elle retourne true
. En dépit du fait que:
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
Un tel comportement inattendu peut dérouter non seulement un programmeur JavaScript ordinaire, mais aussi un combattant expérimenté. En fait, cela m'a incité à écrire cet article. Quelqu'un pourrait comparer ce comportement à une fonctionnalité JS célèbre:
typeof null === 'object' // true
Cependant, ne vous précipitez pas pour ajouter ce cas à la liste wtfjs , car il y a (soudainement) une explication logique à cela. Mais d'abord, voyons pourquoi la méthode a été créée isArray()
et ce qui est caché sous le capot.
Contexte
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 .