لماذا يعود Array.isArray (Array.prototype) إلى القيمة الصحيحة؟

اليوم سنكتشف ما يلي: ما هي طريقة Array.isArray () ، وكيف تعمل تحت الغطاء ، وما الذي تغير معها بعد إصدار ES6 ، ولماذا تعود صحيحة لـ Array.prototype ، والعديد من الموضوعات الأخرى المتعلقة بهذه الطريقة.



و isArray()منشئ وطريقة Arrayأضيفت منذ النسخة 5TH من ECMAScript القياسية . في الصفحة التي تصف هذه الطريقة على موقع MDN ، تقول:



يعيد الأسلوب Array.isArray () القيمة true إذا كان الكائن مصفوفة و false إذا لم يكن مصفوفة.


في الواقع ، هذه الطريقة مناسبة تمامًا لاختبار القيم المختلفة لمعرفة ما إذا كانت القيمة عبارة عن مصفوفة. ومع ذلك ، فإنه يحتوي على ميزة واحدة (أين يمكننا الذهاب بدونها). إذا مررت بهذه الطريقة Array.prototype، وهي كائن ، يتم إرجاعها true. بغض النظر عن حقيقة أن:



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


مثل هذا السلوك غير المتوقع يمكن أن يربك ليس فقط مبرمج JavaScript عاديًا ، ولكن أيضًا مقاتل متمرس. في الواقع ، دفعني هذا لكتابة هذا المقال. قد يقارن شخص ما هذا السلوك بميزة JS الشهيرة:



typeof null === 'object' // true


ومع ذلك ، لا تتسرع في إضافة هذه الحالة إلى قائمة wtfjs ، لأن هناك (فجأة) تفسير منطقي لذلك. لكن أولاً ، دعنا نتعرف على سبب إنشاء الطريقة isArray()وما هو مخفي تحت الغطاء.



Spoiler: لمن يريدون معرفة الإجابة الآن
Array.prototype !


خلفية



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