- Konu sahibi
- #1
JavaScript’te prototype, bir nesnenin özellik ve metotları başka nesnelerden miras almasını sağlayan nesnedir. Bir nesnede aranan özellik doğrudan bulunamazsa JavaScript, nesnenin prototype zincirinde yukarı doğru arama yapar. Böylece aynı metodu her nesneye ayrı ayrı kopyalamak yerine ortak prototype üzerinde tanımlayabilirsiniz.
JavaScript nesnelerinin dahili prototype bağlantısı başka bir nesneye veya zincirin sonunu belirten
Önemli ayrım:
Aşağıdaki örnekte
Beklenen çıktı şöyledir:
İlk iki satır metodun
Metodu doğrudan constructor içinde tanımlarsanız her örnek için yeni bir fonksiyon oluşturulur:
Bu yaklaşım küçük örneklerde çalışır; ancak çok sayıda nesne oluşturulacaksa ortak metotları prototype üzerinde tutmak genellikle daha uygun bir tasarımdır.
Kavramları karıştırmamak için aşağıdaki ayrımı kullanabilirsiniz.
Bu örnekte
Prototype ile nesnenin kendi özelliğini karıştırmak:
Paylaşılan veriyi prototype üzerine koymak: Dizi veya değişebilir nesne gibi ortak bir değeri prototype üzerinde tutmak, tüm örneklerin aynı veriyi paylaşmasına yol açabilir. Örnek verileri constructor içinde, ortak metotları prototype üzerinde tutmak daha güvenlidir.
Sonraki adım: Kendi nesnelerinizde hangi özelliklerin örneğe özel, hangi metotların ortak olması gerektiğini ayırın. Ardından
Nesnenin kendi özelliği, prototype üzerindeki aynı isimli özelliği gölgeler. Kendi özellik silinirse arama yeniden prototype zincirine ilerler.
Çoğu nesnenin vardır; ancak zincirin sonundaki
Prototype nasıl çalışır?
JavaScript nesnelerinin dahili prototype bağlantısı başka bir nesneye veya zincirin sonunu belirten
null değerine işaret eder. Bu bağlantı standart gösterimde [[Prototype]] olarak ifade edilir. Arama sırası şöyledir:- Özellik önce nesnenin kendi üzerinde aranır.
- Bulunamazsa nesnenin
[[Prototype]]nesnesine bakılır. - Orada da bulunamazsa zincirdeki bir sonraki prototype kontrol edilir.
- Zincir
nulldeğerine ulaştığında arama sona erer.
map(), filter() ve push() metotları genellikle her diziye ayrı ayrı yazılmaz. Bu davranışlar Array.prototype üzerinden miras alınır.Önemli ayrım:
prototype çoğunlukla constructor fonksiyonlarının sahip olduğu normal bir özelliktir. [[Prototype]] ise bir nesnenin miras aldığı nesneye yapılan dahili bağlantıdır. new kullanıldığında bu iki kavram ilişkilendirilir.Somut örnek: Ortak metot tanımlama
Aşağıdaki örnekte
User constructor fonksiyonuyla oluşturulan nesneler, greet() metodunu User.prototype üzerinden paylaşır:
Kod:
function User(name) {
this.name = name;
}
User.prototype.greet = function () {
return `Merhaba, ben ${this.name}`;
};
const user1 = new User("Ayşe");
const user2 = new User("Mehmet");
console.log(user1.greet());
console.log(user2.greet());
console.log(user1.greet === user2.greet);
console.log(Object.getPrototypeOf(user1) === User.prototype);
Beklenen çıktı şöyledir:
Kod:
Merhaba, ben Ayşe
Merhaba, ben Mehmet
true
true
İlk iki satır metodun
this değerinin çağrıyı yapan nesne olduğunu gösterir. Üçüncü satır, iki nesnenin aynı fonksiyon referansını prototype üzerinden kullandığını doğrular. Dördüncü satır ise new User() ile oluşan nesnenin prototype bağlantısının User.prototype olduğunu gösterir.Metodu doğrudan constructor içinde tanımlarsanız her örnek için yeni bir fonksiyon oluşturulur:
Kod:
function User(name) {
this.name = name;
this.greet = function () {
return `Merhaba, ben ${this.name}`;
};
}
Bu yaklaşım küçük örneklerde çalışır; ancak çok sayıda nesne oluşturulacaksa ortak metotları prototype üzerinde tutmak genellikle daha uygun bir tasarımdır.
Sık kullanılan kavramların farkı
Kavramları karıştırmamak için aşağıdaki ayrımı kullanabilirsiniz.
| Kavram | Anlamı | Pratik kullanım |
|---|---|---|
User.prototype | Constructor fonksiyonunun ortak özellik alanı | Örneklerin paylaşacağı metotları tanımlamak |
Object.getPrototypeOf(user) | Belirli nesnenin prototype bağlantısını okumak | Miras zincirini incelemek |
class | Prototype tabanlı yapıyı daha okunabilir sözdizimiyle kullanmak | Yeni kodda sınıf benzeri yapı kurmak |
__proto__ | Eski ve önerilmeyen erişim yolu | Yeni kodda kullanmamak |
class ile prototype ilişkisi
class sözdizimi prototype mekanizmasını ortadan kaldırmaz; onu daha okunabilir biçimde kullanır:
Kod:
class User {
constructor(name) {
this.name = name;
}
greet() {
return `Merhaba, ben ${this.name}`;
}
}
Bu örnekte
greet() metodu örneklerin kendi içine kopyalanmak yerine sınıfın prototype yapısıyla ilişkilendirilir. Bu nedenle class kullanırken de prototype zincirini anlamak; miras alma, metot ezme ve hata ayıklama sırasında faydalıdır.Sık yapılan hatalar
Prototype ile nesnenin kendi özelliğini karıştırmak:
user.name doğrudan nesne üzerinde bulunabilirken user.greet prototype zincirinden gelebilir.Paylaşılan veriyi prototype üzerine koymak: Dizi veya değişebilir nesne gibi ortak bir değeri prototype üzerinde tutmak, tüm örneklerin aynı veriyi paylaşmasına yol açabilir. Örnek verileri constructor içinde, ortak metotları prototype üzerinde tutmak daha güvenlidir.
__proto__ kullanmak: Object.getPrototypeOf() bağlantıyı yalnız okur; Object.create() yeni nesneyi seçilen prototype ile kurar; Object.setPrototypeOf() mevcut bağlantıyı değiştirir. Bu işlemler aynı amaçla kullanılmaz. Prototype bağlantısını çalışma sırasında sık sık değiştirmekten de kaçının.Sonraki adım: Kendi nesnelerinizde hangi özelliklerin örneğe özel, hangi metotların ortak olması gerektiğini ayırın. Ardından
Object.getPrototypeOf() ile zinciri inceleyerek beklenmeyen miras davranışlarını doğrulayın.Sık sorulan sorular
Prototype zincirinde aynı isimli özellik varsa hangisi kullanılır?
Nesnenin kendi özelliği, prototype üzerindeki aynı isimli özelliği gölgeler. Kendi özellik silinirse arama yeniden prototype zincirine ilerler.
Her JavaScript nesnesinin prototype’ı var mıdır?
Çoğu nesnenin vardır; ancak zincirin sonundaki
Object.prototype nesnesinin prototype’ı null değeridir. Object.create(null) ile doğrudan prototype’sız bir nesne de oluşturulabilir.Özelliğin nesnenin kendisine mi ait olduğunu nasıl anlarım?
Object.hasOwn(user1, "name") örnekte true, Object.hasOwn(user1, "greet") false döner. Buna karşılık "greet" in user1 miras alınan özelliği de gördüğü için true döner. Bu ayrım, nesnenin yalnız kendi alanlarını işlerken yararlıdır.
Son düzenleme: