عملگر instanceOf به ما این امکان را میدهد که بررسی کنیم یک شیء به کلاسی مشخص تعلق دارد یا خیر. این عملگر ارثبری را هم محسوب میکند.
چنین بررسیای ممکن است در موارد بسیاری ضروری باشد. برای مثال، میتوانیم برای ساخت یک تابع چندریخت (polymorphic) از آن استفاده کنیم، تابعی که بر اساس نوع آرگومانها با آنها به صورت متفاوت رفتار میکند.
عملگر instanceof
سینتکس اینگونه است:
obj instanceof Class
اگر obj به Class یا کلاسی که از آن ارثبری میکند تعلق داشته باشد، این عملگر مقدار true را برمیگرداند.
برای مثال:
class Rabbit {}
let rabbit = new Rabbit();
// است؟ Rabbit آیا شیءای از کلاس
alert( rabbit instanceof Rabbit ); // true
با تابعهای سازنده هم کار میکند:
// به جای کلاس
function Rabbit() {}
alert( new Rabbit() instanceof Rabbit ); // true
…و با کلاسهای درونساخت مانند Array:
let arr = [1, 2, 3];
alert( arr instanceof Array ); // true
alert( arr instanceof Object ); // true
لطفا در نظر داشته باشید که arr هم به کلاس Object تعلق دارد. به این دلیل که Array به صورت پروتوتایپی از Object ارثبری میکند.
معمولا، instanceof زنجیره پروتوتایپ را بررسی میکند. ما هم میتوانیم یک منطق سفارشی در متد ایستای Symbol.hasInstance ایجاد کنیم.
الگوریتم obj instanceof Class تقریبا اینگونه عمل میکند:
-
اگر متد ایستای
Symbol.hasInstanceوجود داشته باشد، سپس آن را فراخوانی کن:Class[Symbol.hasInstance](obj). این متد بایدtrueیاfalseرا برگرداند و کار تمام است. ما اینگونه رفتارinstanceofرا شخصیسازی میکنیم.برای مثال:
// تا instanceof راهاندازی بررسی کردن // فرض کند (animal) را یک جانور canEat هر چیزی شامل ویژگی class Animal { static [Symbol.hasInstance](obj) { if (obj.canEat) return true; } } let obj = { canEat: true }; alert(obj instanceof Animal); // true :فراخوانی شده Animal[Symbol.hasInstance](obj) -
اکثر کلاسها
Symbol.instanceofرا ندارند. در این صورت، منطق استاندارد استفاده میشود:obj instanceOf Classبررسی میکند که آیاClass.prototypeبرابر با یکی از پروتوتایپها در زجیره پروتوتایپیobjهست یا نه.به عبارتی دیگر، یکی پس از دیگری آن را مقایسه میکند:
obj.__proto__ === Class.prototype? obj.__proto__.__proto__ === Class.prototype? obj.__proto__.__proto__.__proto__ === Class.prototype? ... // را برگردان true ،است true اگر جواب // را برگردان false ،در غیر این صورت، اگر ما به انتهای زنجیره رسیدیمدر مثال بالا
rabbit.__proto__ === Rabbit.prototypeبرقرار است، پس بلافاصله جواب مشخص میشود.در صورت وجود ارثبری، تساوی در مرحله دوم رخ میدهد:
class Animal {} class Rabbit extends Animal {} let rabbit = new Rabbit(); alert(rabbit instanceof Animal); // true // rabbit.__proto__ === Animal.prototype (مساوی نیست) // rabbit.__proto__.__proto__ === Animal.prototype (!مساوی است)
این هم تصویر چیزی که rabbit instanceof Animal با Animal.prototype مقایسه میکند:
راستی، همچنین متدی به نام objA.isPrototypeOf(objB) وجود دارد که اگر objA جایی در زنجیره پروتوتایپ objB وجود داشته باشد true را برمیگرداند. پس بررسی obj instanceof Class میتواند به صورت Class.prototype.isPrototypeOf(obj) بازنویسی شود.
جالب است که سازنده Class خودش در بررسی شرکت نمیکند! فقط زنجیره پروتوتایپها و Class.prototype مهم هستند.
زمانی که ویژگی prototype بعد از اینکه شیء ساخته شد تغییر کند، این موضوع میتواند باعث ایجاد پیامدهای جالبی شود.
مثل اینجا: