Pourquoi Array.isArray (Array.prototype) renvoie-t-il vrai?

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.



Spoiler: Pour ceux qui veulent connaître la réponse maintenant
Array.prototype !


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]


! Array.isArray() :



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() . , . ? - ?








All Articles