24 Ocak 2022

Metodlar ve prototipler

Bu bölümde prototipler ile çalışmak için ek metodlardan bahsedeceğiz

Bizim bildiğimizin haricinde prototipi ayarlamak ve almak için başka yöntemler de bulunmaktadır:

Örneğin:

let animal = {
  eats: true
};

// animal prototipi ile yeni bir rabbit objesi yaratma.
let rabbit = Object.create(animal);

alert(rabbit.eats); // true
alert(Object.getPrototypeOf(rabbit) === animal); // rabbit'in prototipini alma

Object.setPrototypeOf(rabbit, {}); // rabbit'in prototipini {}'e çevirme.

Object.create opsiyonel olarak ikinci bir argümana sahiptir: özellik tanımlayıcı. Aşağıdaki gibi yeni objeye özellikler ekleyebiliriz:

let animal = {
  eats: true
};

let rabbit = Object.create(animal, {
  jumps: {
    value: true
  }
});

alert(rabbit.jumps); // true

Tanımlayıcıların Özellik bayrakları ve tanımlayıcılar bölümünde üstünden geçilmiştir. Formatları aynıdır. Object.create kullanarak obje klonlama işlemini yapabiliriz. Bu objenin özelliklerini for..in ile dolanmaktan daha etkin bir yöntemdir.

// Objenin yüzeysel klonu
let clone = Object.create(Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj));

Bu tam olarak obj’nin aynısını verir. Tüm özellikler: dönülebilir veya dönülemez, veri özellikleri, alıcı ve ayarlayıcılar – her şey, ayrıca doğru [[Prototype]] ile

Tarihçe

[[Prototype]]'ı ayarlayabileceğimiz yöntemleri saymaya kalsak baya zorluk yaşarız. Çok fazla yöntem bulunmaktadır.

Neden?

Birçok nedeni bulunmaktadır.

  • Yapıcının "prototype" özelliği ilk javascript ortaya çıktığından beri bulunmaktadır.
  • 2012’de: Object.create bir standart olarak oturdu. Bu verilen prototip ile objeleri yaratmaya izin verdi. Fakat bunları almaya veya ayarlamaya değil. Bundan dolayı tarayıcılar bir standart olmayan __proto__ erişimcilerini uygulayarak alıcı ve ayarlayıcılara ( get/set)'e izin verdi.
  • 2015’te: Object.setPrototypeOf ve Object.getPrototypeOf bir standart olarak eklendi. __proto__ defakto şeklinde aslında her yerde kullanılmıştı, Bundan dolayı çokta kulllanılan özellikler olmadı, sadece tarayıcı harici çevrelerde kullanılır oldu.

Artık bunların hepsi bizim kullanımımızdadır.

Teknik olarak [[Prototype]]'ı istediğimiz an alma/ayarlama işi yapabiliriz. Fakat genelde bunu sadece obje yaratırken kullanır ve daha sonra düzenleme yapmayız: rabbit, animaldan kalıtım alır fakat onu değiştirmez. JavaScript motorları da bunu yüksek derecede optimize edebilir. Prototipi Object.setPrototypeOf veya obj.__proto__ ile sonradan değiştirmek oldukça yavaş bir operasyondur. Ama mümkündür.

“En basit” Objeler

Bildiğiniz gibi objeler anahtar/değer ikilisini tutan ilişkisel dizi şeklinde kullanılabilir.

…Eğer içerisinde kullanıcı-kaynaklı anahtarlar ( örneğin kullanıcının girdiği sözlük tipi veriler) var ise, ilginç bir aksaklık meydana gelir: "__proto_" haricinde tüm anahtarlar doğru çalışır.

Örneğin:

let obj = {};

let key = prompt("What's the key?", "__proto__");
obj[key] = "some value";

alert(obj[key]); // [object Object] olarak döner ,  "some value" değil!

Eğer kullanıcı tipleri __proto__ içerisinde ise atama görmezden gelinir!

Bu aslında çok da sürpriz olmasa gerek. __proto__ farklı bir özelliktir: Ya obje olur veya null, mesela bir karakter dizisi prototip olamaz.

Fakat buradaki amacımız böyle bir davranışı uygulamak değildi, değil mi? Biz key/value ikililerini kaydetmekti. "__proto__"