Warum gibt Array.isArray (Array.prototype) true zurück?

Heute werden wir Folgendes herausfinden: Was ist die Array.isArray () -Methode, wie funktioniert sie unter der Haube, was hat sich nach der Veröffentlichung von ES6 daran geändert, warum sie für Array.prototype true zurückgibt und viele weitere Themen im Zusammenhang mit dieser Methode.



Die isArray()Konstruktormethode Arraywurde seit der 5. Version des ECMAScript-Standards hinzugefügt . Auf der Seite, die diese Methode auf der MDN- Website beschreibt , heißt es:



Die Array.isArray () -Methode gibt true zurück, wenn das Objekt ein Array ist, und false, wenn es kein Array ist.


In der Tat eignet sich diese Methode gut zum Testen verschiedener Werte, um festzustellen, ob es sich bei dem Wert um ein Array handelt. Es hat jedoch eine Funktion (wohin können wir ohne sie gehen). Wenn Sie diese Methode übergeben Array.prototype, die ein Objekt ist, wird sie zurückgegeben true. Trotz der Tatsache dass:



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


Ein solches unerwartetes Verhalten kann nicht nur einen gewöhnlichen JavaScript-Programmierer, sondern auch einen erfahrenen Kämpfer verwirren. Eigentlich hat mich das dazu veranlasst, diesen Artikel zu schreiben. Jemand könnte dieses Verhalten mit einer berühmten JS-Funktion vergleichen:



typeof null === 'object' // true


Es besteht jedoch kein Grund zur Eile, diesen Fall zur wtfjs- Liste hinzuzufügen , da es (plötzlich) eine logische Erklärung dafür gibt. Aber zuerst wollen wir herausfinden, warum die Methode erstellt wurde isArray()und was sich unter der Haube verbirgt.



Spoiler: Für diejenigen, die die Antwort jetzt wissen wollen
Array.prototype !


Hintergrund



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