JavaScript’te Object Kavramı — 2
Herkese merhaba, bu yazı JavaScript’te Object Kavramı 1'in devamı niteliğinde olacaktır. Buradaki kavramların daha iyi anlaşılması için bir önceki yazıyı okumanızı tavsiye ederim. JavaScript’te Object Kavramı 1'e buradan ulaşabilirsiniz.
Prototype Nedir?
Evet arkadaşlar öncelikle prototype’ın tanımını yaparak başlayalım. Prototype, JavaScript’te hemen hemen tüm nesneler başka bir nesneden türetilerek oluşturulur. Biz yeni bir nesne oluşturduğumuz zaman, kendinden daha önceki nesne diyebileceğimiz ya da onun ata nesnesi olarak tanımlayabileceğimiz bir nesneden türetilir. Bu bir önceki nesneye de türetilen nesnenin prototype’ı denir. Bir örnek verecek olursak eğer;
Yukarıdaki örneğe baktığımızda 10. satırda fullName metodunu çalıştırıyoruz bunda herhangi yeni bir durum yok. 11. satırda fullName2 isminde bir metot varmış gibi düşünüp çalıştırmaya çalıştığımızda hata alıyoruz doğal olarak. 12. satırda toString metodunu çalıştırdığımızda herhangi bir hata almıyoruz. Ee bizim nesnemize bağlı olarak herhangi bir toString metodu olmamasına rağmen neden hata almıyoruz? Biz böyle bir metot yazmadık bu metot nereden geliyor? Şimdi sağ taraftaki çıktıya bakacak olursak age, fullName, name, surname propertyleri var bunları zaten biz kendimiz vermiştik. Ama [[Prototype]] diye bir şey var ona baktığımız zaman toString isminde bir metot görüyoruz. Buradaki olay, biz person nesnesini oluşturduğumuz zaman bu person nesnesinin prototype’ı bir Object. Yani biz person nesnesini oluşturur oluşturmaz bu person nesnesi prototype olarak Object nesnesini alıyor. Böylece Object nesnesine ait olan metotların aynısını person nesnesinde de kullanabiliyoruz. Terminolojik olarak söyleyecek olursak bizim oluşturduğumuz person nesnesi, prototype’ı olan Object nesnesinden toString metodunu inherit ediyor, yani miras olarak alıyor. Aklımızda daha iyi kalması için şöyle düşünebiliriz.
Object nesnesi + name, surname, age, fullName() → person nesnesi
Şimdi de yukarıdaki örneği Object Literal yerine constructor fonksiyon yardımıyla bir nesne oluşturup inceleyelim.
Yukarıdaki örnekte micheal adında bir nesne oluşturup ekrana yazdırdığımızda Person diye bir şey yazıyor dikkat ettiyseniz. Neden ? Çünkü bizim nesnemiz prototype olarak temel nesne değil (Object) temel nesnenin yanında person isminde bir constructor fonksiyon oluşturduk oradan da belirli özellikler alıyor. Bunu da şöyle düşünebiliriz.
Object nesnesi + name, surname, age, fullName() → person → micheal
Biz constructor fonksiyonu yardımıyla yeni bir nesne oluşturduk ve bu yeni nesne özelliklerini person constructor fonksiyonundan artı Object’ten alıyor. Yani micheal’ın prototype’ı person, person’ın prototype’ı Object diyebiliriz. Buradaki üçlü ifadeyi de bir prototype zinciri olarak düşünebiliriz. Böylece biz micheal nesnesinde de Object temel nesnesinin içindeki toString metodunu inheritance yardımıyla hata almadan kullanabiliyoruz.
Şimdi örneğimizi biraz daha ileri götürelim ve bir nesne daha oluşturalım.
Yukarıdaki örneği inceleyecek olursak dwight isminde yeni bir person nesnesi oluşturduk. Daha sonra dwight nesnesine job isminde yeni bir property ekliyoruz. 17. satıra baktığımızda dwight nesnesinde yukarıdakilerden farklı olarak bir de job propertysi var. Yani şöyle düşünebiliriz;
Object nesnesi + name, surname, age, fullName() → person + job → dwight
Temel Object nesne üzerine name, surname, age, fullName özelliklerini ekledik ve person constructor fonksiyonu oldu, person constructor fonksiyonuna da job şeklinde bir özellik eklediğimiz zaman dwight nesnesini oluşturduk. Yani dwight nesnesi, person artı job’ın toplamından oluşuyor gibi düşünebiliriz. Son olarak dwight nesnesinin prototype’ı person nesnesi, person nesnesinin prototype’ı Object’tir. Bir prototype zincirinden ilerliyoruz.
NOT: Yukarıda person’a bazen person nesnesi bazen person fonksiyonu diyoruz. Fonksiyonların da birer nesne olduğunu unutmayalım.
Yukarıda bir prototype zincirinden ilerlediğimizi söylemiştik. Bununla birlikte biz prototype’ta var olan bir metodun üzerine yazabiliriz, ne demek istiyoruz ?
Yukarıdaki örneğe baktığımızda 13. satırda dwight nesnesinin toString metodunu kullanıyoruz ve [object Object] çıktısını alıyoruz bu gayet beklediğimiz bir sonuç. 15. satırda dwight nesnesinin toString metodunun üzerine yazarak Dwight To String şeklinde bir yazı dönmesini istiyoruz.
19. satırda tekrar toString metodunu çalıştırdığımızda ise Dwight To String şeklinde bir çıktı alıyoruz. Bu şekilde biz prototype’ta var olan bir metot üzerine yazabiliriz.
Nesneye Prototype Ekleme
Bu işlem bazen prototype genişletme olarak da adlandırılır. JavaScript’te bir nesnenin prototype’ına yeni metotlar eklemek, nesne yönelimli programlama kavramının bir parçasıdır. Bu sayede nesneler arasında metotları paylaşabilir ve kodumuzu daha verimli bir şekilde düzenleyebiliriz. Bir örnek verecek olursak;
Şimdi yukarıdaki örnekte constructor fonksiyona baktığımızda name, surname ve age parametreleri farklı fullName metodu ortak. Yani biz herhangi bir nesne oluşturduğumuzda kendisine ait fullName metodunu çalıştıracak. Aynı işi yapan fonksiyonun her nesne için tekrar tekrar çalışmasına gerek yok, bu metodu nesnenin constructor fonksiyonundan çıkarıp prototype’ına aldık. Bu iki nesneye bakacak olursak;
Gördüğümüz gibi fullName metodunu prototype’ın içine aldık. Çünkü bu metot iki nesne için de ortak her iki nesne için ayrı ayrı oluşturmasına gerek yok. Biz fullName metodunun bir kere prototype’ını alırız bu tek metot tüm nesneler için çalışır ve belleği boş yere yormamış oluruz.
Inheritance (Kalıtım/Miras) Nedir?
Inheritance, nesnenin özelliğinin farklı nesneler tarafından kullanılabilmesine denir. Daha önceki örneklerde de gördüğümüz üzere JavaScript ES5 sürümü inheritance kavramını prototypal inheritance olarak kullanır. Yani özelliği ve metodu kendi prototype’ından alıyor. Inheritance kavramına biraz aşina olan arkadaşlar için inheritance kavramı genelde classlar arasındaki ilişkide kullanılır. ES6 ile beraber gelen classlar konusuna da başka bir yazıda değineceğiz. Şimdi son bir örnek yaparak konuyu özetlemeye çalışalım.
Yukarıdaki örneğe baktığımız zaman Object Create metodu ile yeni bir micheal nesnesi oluşturuyoruz. 11. satırda ekrana yazdırdığımızda boş bir nesne gösterdi. 12. satırda micheal’ın name property’sini yazdırmak istediğimizde ise XXXXXX çıktını aldık. İşte bu name property’sini kendi prototype’ından alıyor. Yani person nesnesindeki değeri alıyor. Ancak 14. satırdaki gibi micheal nesnesinin name property’sine Micheal değerini verdikten sonra 15. satırda ekrana yazdırdığımızda ise bu kez name property’sini XXXXX şeklinde değil Micheal olarak bir nesnenin içinde gösterdi. Çünkü artık name’i prototype’tan almıyor kendimiz bir değer atadık. Yani prototype zincirinde önce kendi özelliğinden alır. 17. satıra baktığımızda micheal nesnesinin name property’si var mı diye baktığımızda true sonucunu alıyoruz ancak 18. satırda surname property’sine baktığımızda ise false değerini alıyoruz. Bunun sebebi surname property’sinin micheal nesnesinde değil onun prototype’ında olmasıdır.
20. satırda yaptığımız ise bir nesnenin prototype’ında veya değil herhangi birinde surname property’si var mı diye bakıyoruz. Kendisinde yok ancak prototype’ında olduğu için true değerini alıyoruz.
ES5 prototypal inheritance yöntemini kullanarak ortak özellikleri prototype’ta toplamaya çalışır ve bir nesneyi başka bir nesneden türetmeye çalışır. Türetilen ilk baştaki temel nesne ise built-in Object’tir.
Evet arkadaşlar bu yazıda sizlere elimden geldiği kadar sade bir şekilde JavaScript’te prototype tabanlı nesne yönelimli programlama modelini anlatmaya çalıştım, umarım faydalı olmuştur. İyi çalışmalar.
Referanslar;
1) Arin Yazılım
2) MDN Web Docs
3) JavaScript Info