Mengapa Array.isArray (Array.prototype) mengembalikan nilai true?

Hari ini kita akan mencari tahu yang berikut: apa itu metode Array.isArray (), bagaimana cara kerjanya di bawah tenda, apa yang telah berubah dengannya setelah ES6 dirilis, mengapa ia mengembalikan true untuk Array.prototype, dan banyak lagi topik yang terkait dengan metode ini.



Metode isArray()konstruktor Arraytelah ditambahkan sejak versi 5 dari standar ECMAScript . Di halaman yang menjelaskan metode ini di situs web MDN tertulis:



Metode Array.isArray () mengembalikan nilai true jika objek adalah array dan false jika bukan array.


Memang, metode ini sangat cocok untuk menguji berbagai nilai untuk melihat apakah nilainya berupa array. Namun, itu memiliki satu fitur (di mana kita bisa pergi tanpanya). Jika Anda meneruskan metode ini Array.prototype, yang merupakan objek, metode ini akan kembali true. Terlepas dari kenyataan bahwa:



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


Perilaku tak terduga seperti itu tidak hanya dapat membingungkan programmer JavaScript biasa, tetapi juga pejuang berpengalaman. Sebenarnya, ini mendorong saya untuk menulis artikel ini. Seseorang mungkin membandingkan perilaku ini dengan fitur JS yang terkenal:



typeof null === 'object' // true


Namun, jangan terburu-buru menambahkan kasus ini ke daftar wtfjs , karena (tiba-tiba) ada penjelasan logis untuk ini. Tapi pertama-tama, mari kita cari tahu mengapa metode itu dibuat isArray()dan apa yang tersembunyi di balik kap mesin.



Spoiler: Bagi yang ingin tahu jawabannya sekarang juga
Array.prototype !


Latar Belakang



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