"prototype" özelliÄi JavaScript çekirdeÄinde oldukça fazla kullanılmaktadır. Tüm varsayılan yapıcı fonksiyonlar bunu kullanır.
Ãnce basit objeler, sonra daha karmaÅık olanları için nasıl çalıÅtıÄını göreceÄiz.
Object.prototype
Diyelim ki boŠbir objeyi yazdırdınız:
let obj = {};
alert( obj ); // "[object Object]" ?
"[object Object]" yazısını oluÅturan kod nerede? Bu varsayılan toString metodu, ama asıl soru nerede? bu obj boÅ!
â¦Fakat obj = {} ile obj = new Object() aslında aynı anlama gelmektedir. Object object yapıcı fonksiyonudur. Bu fonksiyon Object.prototypeâe ki bu da büyük bir toStringâe sahip objeye ve diÄer fonksiyonlara sahiptir.
AÅaÄıdaki gibi( Tamamı gömülüdür):
new Object() çaÄrıldıÄında ( veya {...} ile yaratıldıÄında ) Objenin [[Prototype]]'i bir önceki bölümde bahsettiÄimiz gibi Object.prototypeâa ayarlanır.
Sonrasında obj.toString() çaprıldıÄında â Bu metod Object.prototypeâtan alınır.
Bunu Åu Åekilde kontrol edebiliriz:
let obj = {};
alert(obj.__proto__ === Object.prototype); // true
// obj.toString === obj.__proto__.toString == Object.prototype.toString
Object.prototypeâın üstünde baÅka bir [[Prototype]] yoktur.
alert(Object.prototype.__proto__); // null
DiÄer gömülü prototipler
Array, Date, Function gibi diÄer gömülü objeler metodlarını prototype üzerinde tutar.
ÃrneÄin, [1,2,3] bir array yarattıÄınızda içte varsayılan new Array() yapıcısı kullanılır. Bundan dolayı dizi dizi objesi yeni bir objeye yazılır ve Array.prototype bunun prototipi olur ve metodlar saÄlar. Bu hafızayı oldukça etkin kullanmaya yarar.
Tanım gereÄi, tüm gömülü prototipler üstünde Object.prototypeâa sahip olmalıdır. Bazen âher Åey objelerden kalıtım alırâ sözünü duyarsınız.
AÅaÄıda bunun etraflı bir görselini görebilirsiniz.
Prototipleri inceleyecek olursak:
let arr = [1, 2, 3];
// Array.prototype'tan mı kalıtım alıyor?
alert( arr.__proto__ === Array.prototype ); // true
// peki ya Object.prototype'tan mı?
alert( arr.__proto__.__proto__ === Object.prototype ); // true
// Peki ya onun üzerine bir null.
alert( arr.__proto__.__proto__.__proto__ ); // null
Bazı metodlar üst üste gelebilir, örneÄin Array.prototype kendine ait bir toString metoduna sahiptir ve bu da elemanları arasına virgül koyarak çıktı vermesini saÄlar:
let arr = [1, 2, 3]
alert(arr); // 1,2,3 <-- Array.prototype.toString'in sonucu
Daha önce de gördüÄümüz gibi, Object.prototypeâın toString metodu bulunmaktadır fakat Array.prototype bu zincirlemede daha yakındır ve bundan dolayı diziler bunu kullanır.
Chrome Developer Tools konsolunda da bu kalıtımı ( console.dir kullanarak görebilirsiniz )
DiÄer gömülü objeler de aynı Åekilde çalıÅır, hatta fonksiyonlar bile. Bunlar gömülü Fonksiyon yapıcısının objeleridir, call/apply gibi metodları ve diÄerleri Function.prototypeâtan alınmıÅtır. Fonksiyonların kendine ait toString metdoları da bulunmaktadır.
function f() {}
alert(f.__proto__ == Function.prototype); // true
alert(f.__proto__.__proto__ == Object.prototype); // true, objelerden kalıtım alır.
İlkel tipler
En karıÅık yapılar karakter dizileri, sayılar ve boolean ile yapılır.
HatırlayacaÄınız üzere bunlar obje deÄildirler. Fakat özelliklerine eriÅmeye çalıÅtıÄınızda, gömülü yapıcı obje ile geçici objeler üretilir. Bunlar String, Number, Boolean metodlarını saÄlar ve yok olurlar.
Bu objeler gizli üretilir ve çoÄu motor bunları optimize edebilir, Fakat Åartname bunu tam olarak bu Åekilde tanımlar. Bu objelerin metodları da prototypeâta yer alır, String.prototype, Number.prototype ve Boolean.prototype olarak bulunur.
nullDoÄal prototiplerin deÄiÅtirilmesi
DoÄal(native) prototipler modifiye edilebilir. ÃrneÄin, String.prototypeâa bir metod eklersek, bu tüm karakter dizileri için geçerli olur:
String.prototype.show = function() {
alert(this);
};
"BOOM!".show(); // BOOM!
GeliÅtirme sürecinde hangi fikirlerin gömülü olması gerektiÄine dair fikrimiz olabilir. Hatta doÄal prototiplere ekleme yapmak için istek duyabilirsiniz. Fakat bu genelde kötü bir fikiridir.
Prototipler evrenseldir, bundan dolayı kolayca ikilik çıkarabilir. EÄer iki kütüphane String.prototype.show Åeklinde metod eklerse bunlardan biri diÄerinin üzerine yazar.
Modern programlama da sadece bir koÅulda doÄal prototiplerin düzenlenmesine izin verilir. Buna pollyfills denir. DiÄer bir deyiÅle eÄer JavaScript Åartnamesinde bir metod var fakat bu JavaScript motoru tarafından henüz desteklenmiyorsa, bunu elle yazmak ve gömülü prototipe eklemek mümkündür.
ÃrneÄin:
if (!String.prototype.repeat) { // EÄer böyle bir metod yoksa
// prototip'e ekle
String.prototype.repeat = function(n) {
// karakteri n defa tekrarlar
// aslında kod bundan daha karmaÅık olmalıdır.
// eÄer n negatif bir sayı gelirse hata dönder
// Algoritma Åartnamede belirlenmiÅtir.
return new Array(n + 1).join(this);
};
}
alert( "La".repeat(3) ); // LaLaLa
Prototiplerden ödünç alma
Dekoratörler ve iletilme, call/apply bölümünde metod ödünç almadan bahsetmiÅtik.
function showArgs() {
// Array'den join i ödünç al ve argüman kaynaÄında çaÄır.
alert( [].join.call(arguments, " - ") );
}
showArgs("John", "Pete", "Alice"); // John - Pete - Alice
join Array.prototype içerisinde bulunduÄundan dolayı, oradan doÄrudan çaÄırabilir ve Åu Åekilde tekrar yazabiliriz:
function showArgs() {
alert( Array.prototype.join.call(arguments, " - ") );
}
Bu daha etkin çünkü ayrıca bir dizi [] objesi yaratmaktan kaçınılmıÅtır. Fakat biraz uzun sürmüÅtür.
Ãzet
- Tüm gömülü objeler aynı yapıyı paylaÅır:
- Metodlar prototiplerde saklanır (
Array.prototype,Object.prototype,Date.prototypevs. ) - Veriyi objenin kendisi tutar ( dizi elemanları, obje özellikleri, tarih vs. )
- Metodlar prototiplerde saklanır (
- İlkel veriler de saklayıcı objelerin prototiplerinde metodlarını tutarlar:
Number.prototype,String.prototype,Boolean.prototype. Sadeceundefinedvenulliçin saklayıcı objeler bulunmamaktadır. - Gömülü prototipler yeni metodlar ile deÄiÅtirilebilir. Fakat bunların deÄiÅtirilmesi önerilmez. Tek deÄiÅtirilebilir diyeceÄimiz olay yeni bir standartâın eklenmesi olabilir, JavaScript motoru henüz o özelliÄi uygulamamıÅsa bu standartâı siz uygulayabilirsiniz.
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)