instanceof operatörü bir objenin belirli bir sınıfa ait olup olmadıÄını kontrol eder. Kalıtımı da hesaba kadar.
Böyle bir kontrole birçok durumda ihtiyacımız olabilir. AÅaÄıda polymorphic fonksiyon inÅa etmek için, argümanların tipine göre farklı davranıŠsergileyen bir yapı yer almaktadır.
instanceof operatorü
Yazımı Åu Åekildedir:
obj instanceof Class
EÄer objâe Classâa aitse true döner. ( Veya Classâtan türüyorsa)
ÃrneÄin:
class Rabbit {}
let rabbit = new Rabbit();
// `Rabbit` sınıfının bir objesimidir?
alert( rabbit instanceof Rabbit ); // true
Bu yapıcı fonksiyonlar için de çalıÅır:
// instead of class
function Rabbit() {}
alert( new Rabbit() instanceof Rabbit ); // true
â¦Array gibi gömülü sınıflar için de
let arr = [1, 2, 3];
alert( arr instanceof Array ); // true
alert( arr instanceof Object ); // true
Dikkat edin arr ayrıca Object sınıfına da aittir. Ãünkü Array prototipi Objectâten kalıtım alır.
instanceof operatörü prototip zincirini kontrol eder. Symbol.hasInstance statik metodu ile daha performanslı yapılabilir.
obj instanceof Class algoritması kabaca aÅaÄıdaki gibi çalıÅır:
-
EÄer
Symbol.hasInstancestatik metodu var ise onu kullan. Åu Åekilde:// canEat yapabilen her Åeyi animal varsayalım. class Animal { static [Symbol.hasInstance](obj) { if (obj.canEat) return true; } } let obj = { canEat: true }; alert(obj instanceof Animal); // true: Animal[Symbol.hasInstance](obj) çaÄırıldı. -
ÃoÄu sınıf
Symbol.hasInstanceâa sahip deÄildir. Bu durumda eÄerClass.prototypeobjânin bir prototipine zincirde olup olmadıÄını kontrol eder.DiÄer bir deyiÅle:
obj.__proto__ == Class.prototype obj.__proto__.__proto__ == Class.prototype obj.__proto__.__proto__.__proto__ == Class.prototype ...Yukarıdaki örnekte
Rabbit.prototype == rabbit.__proto__, cevabı doÄrudan verir.Kalıtım yönünden ise
rabbitüst sınıfın da instanceofâu dur.class Animal {} class Rabbit extends Animal {} let rabbit = new Rabbit(); alert(rabbit instanceof Animal); // true // rabbit.__proto__ == Rabbit.prototype // rabbit.__proto__.__proto__ == Animal.prototype (match!)
AÅaÄıda rabbit instanceof Animalâın Animal.prototypea karÅılaÅtırılması gösterilmiÅtir.
Ayrıca objA.isPrototypeOf(objB) metodu ile eÄer objA objBânin prototip zincirinin herhangi bir yerindeyse true döner. obj instanceof Class Åu Åekilde de yazılabilir Class.prototype.isPrototypeOf(obj)
Class yapıcısının kendisi bu kontrolde yer almaz, garip deÄil mi? Sadece Class.prototype ve prototiplerin zinciri önemlidir.
Bu prototip deÄiÅtiÄinde farklı sonuçlara yol açabilir.
AÅaÄıdaki gibi:
function Rabbit() {}
let rabbit = new Rabbit();
// prototip deÄiÅti
Rabbit.prototype = {};
// ...artık rabbit deÄil!
alert( rabbit instanceof Rabbit ); // false
Prototipâi deÄiÅtirmemeniz ve daha güvenli tutmanız için bir diÄer neden daha olmuÅ oldu.
Bonus: Tip için Object toString
BildiÄiniz gibi basit objeler karakter dizisine [object Object] Åeklinde çevrilir.
let obj = {};
alert(obj); // [object Object]
alert(obj.toString()); // the same
Bu toStringâi bu Åekilde tanımlamalarından dolayıdır. Fakat görünenden daha güçlü bir toString yazmak için gizli özellikler bulunmaktadır. Bunu typeofâun daha geniÅi ve instanceofâun alternatifi olarak görmek mümkün.
Garip geliyor deÄilmi. Bakalım neymiÅ
Åartname, incelendiÄinde gömülü gelen toString metodunun objeden çıkarılabileceÄi ve baÅka bir deÄerin kaynaÄında çalıÅtırabileceÄi görülmektedir. Sonucu da bu deÄere göre gelir.
- Sayı için
[object Number] - Boolean deÄerler için
[object Boolean] nulliçin:[object Null]undefinediçin:[object Undefined]- Diziler için:
[object Array] - â¦vs (düzenlenebilir).
Bir örnekle gösterelim:
// kolaylık olması için `toString` metodunu bir deÄiÅkene kopyalayalım
let objectToString = Object.prototype.toString;
// Bu hangi tipte?
let arr = [];
alert( objectToString.call(arr) ); // [object Array]
Burada callâi kullandık ve Dekoratörler ve iletilme, call/apply bölümünde objectToString fonksiyonunun nasıl this=arr kaynaÄında kullanılacaÄı gösterilmiÅti.
Dahili olarak toString algoritması thisâi kontrol eder ve buna denk gelen sonucu döner. ÃrneÄin:
let s = Object.prototype.toString;
alert( s.call(123) ); // [object Number]
alert( s.call(null) ); // [object Null]
alert( s.call(alert) ); // [object Function]
Symbol.toStringTag
Objenin toString metodu özel bir özellikle Symbol.toStringTag düzenlenebilir.
ÃrneÄin:
let user = {
[Symbol.toStringTag]: 'User'
};
alert( {}.toString.call(user) ); // [object User]
ÃoÄu çevre-özel objelerde böyle özellikler bulunur. AÅaÄıda tarayıcı tabanlılar yer almaktadır:
// Ãevre-özel objeler ve sınıflar için toStringTag
alert( window[Symbol.toStringTag]); // window
alert( XMLHttpRequest.prototype[Symbol.toStringTag] ); // XMLHttpRequest
alert( {}.toString.call(window) ); // [object Window]
alert( {}.toString.call(new XMLHttpRequest()) ); // [object XMLHttpRequest]
GördüÄünüz gibi, sonuç kesinlikle Symbol.toStringTagâdır ve varsa [object ...] içerisinde saklanır.
Sonunda daha güçlü bir typeofâa sahip olduk. Artık sadece ilkel datalar için deÄil, gömülü gelen objeler için bile çalıÅabilir durumdadır.
Gömülü gelen objeler için tipi karakter dizi olarak almak istediÄimizde instanceof yerine bunu kullanabiliriz. Instanceof sadece kontrol iÅlemi yapmaktaydı.
Ãzet
BildiÄimiz tip kontrol metodlarının üzerinden geçecek olursak:
| çalıÅır | döner | |
|---|---|---|
typeof |
ilkellerde | string |
{}.toString |
ilkellerde, gömülü ve Symbol.toStringTagâli objelerde |
string |
instanceof |
objelerde | true/false |
GördüÄünüz gibi {}.toString teknik olarak âen geliÅmiÅâ typeofâtur denebilir.
instanceof operatörü sınıf hiyerarÅilerileri ve bu hiyerarÅiyi göz önüne alacak sınıf için bulunmaz bir kaynaktır.
Yorumlar
<code>kullanınız, birkaç satır eklemek için ise<pre>kullanın. EÄer 10 satırdan fazla kod ekleyecekseniz plnkr kullanabilirsiniz)