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.
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]
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 .