JavaScript’te Class Kavramı — 2
Herkese merhaba, bu yazı JavaScript’te Class 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 Class Kavramı 1'e buradan ulaşabilirsiniz.
Bu yazıda sizlere class, static method, inheritance, instance, subclass, super ve extends kavramlarından bahsetmeye çalışacağım.
Bir önceki dersimizde kaldığımız yerden devam edelim o zaman. Biz en son JavaScript’te classların özel bir fonksiyon olduğunu söylemiştik hatta typeof ile bunu kanıtlamıştık. Ayrıca bizim açımızdan class gösteriminde en önemli özelliklerden biri de constructor metoduydu. Ne yapıyordu constructor metot? Öncelikle hafızada bir obje oluşturuyor ikinci olarak this’i o an ki current objeye bağlıyordu.
Şimdi class ile ilgili bir önek verelim ve bu örnek üzerinden kavramları biraz daha detaylı olarak inceleyelim.
Yukarıdaki örneğe bakacak olursan biz önceki yazıda 14. satır için yeni bir micheal nesnesi/objesi oluşturuyoruz diyorduk. Bunun farklı bir şekilde söylemi olarak da micheal’a, Person’ın instance’ı deniyor. 14. satırdaki işleme de instantiate denir. Yani artık micheal, Person’ın bir instance’ı diyoruz.
Sağ taraftaki console çıktısına baktığımız zaman constructor içersindeki age, name ve surname propertyleri görünürde var. Bizim için en önemli özelliklerden biri de, class içinde bir fonksiyon oluşturduğumuz zaman ki bu objeye bağlandığında buna metot deriz. İşte buradaki fullName metodumuz dikkat ederseniz proto’nun içinde yer alıyor. Biz classta kaç tane fonksiyon oluşturursak oluşturalım o fonksiyonlar her zaman proto’nun içinde bulunur.
Şimdi Person classından iki farklı instance oluşturup onları inceleyelim.
Yukarıdaki örneğe baktığımızda her iki instance için age, name ve surname değerleri farklı ancak fullName metodu aynı. Yani age, name ve surname o an instantiate edilen nesneye göre değişiklik gösterebilir ancak fullName fonksiyonu her ikisinde de aynı, ikisinde de proto’nun içinde bulunuyor.
Yukarıdaki örneğe baktığımız zaman bir önceki örneğin aynısı burada farklı olan kısım 18. satırda Person classına bağlı olarak fullName metodunu çalıştırmaya çalıştığımız için hata aldık. Çünkü biz Person classı üzerinden fullName metodunu çağırıyoruz ve this hangisine bağlı onu çıkaramıyor. micheal’in fullName’ini mi yoksa dwight’ın fullName’ini mi istiyoruz JavaScript Engine bunu anlamadığı için hata veriyor. Ancak biz bazı durumlarda belirli metotları yalnızca o classa bağlamak isteriz. O class’tan türetilen nesnelere değil, o class’tan instantiate edilen instance’lara değil yalnızca o classa ait olmasını isteriz. İşte bunlara da static method denir.
Bir örnek üzerinde konunun daha iyi anlaşılacağını düşünüyorum.
Yukarıdaki örneğe baktığımızda 12. satırda static keywordü ile showName adında bir özellik tanımlıyoruz. 14. satırda ise yine static keywordü ile staticMethod isminde bir metot tanımlıyoruz. Static metotlar için ne demiştik? Instance üzerinden ulaşamıyoruz ancak class üzerinden ulaşabiliyoruz demiştik. Instance üzerinden ulaşamadığımızı 24. satırda undefined, 25. satırda ise … is not a function hatası alarak görmüş olduk. Ancak 22. ve 23. satırlarda Person class’ı üzerinden ulaşmaya çalıştığımızda ise Person ve Static method worked çıktılarını alıyoruz. Bu durumun en çok kullanılan örneklerinden biri de React’ta Context Type’tır.
Tamam Da Niye Class?
Biz zaten constructor fonksiyon yardımıyla class ile oluşturduğumuz nesnenin aynısını oluşturuyoruz. Burada bizim açımızdan özel olarak JavaScript’te ve genel olarak da nesne yönelimli programlamada neden class diye bir yapıya ihtiyacımız var? Class diye bir şeye ihtiyacımızın en temel sebebi, nesne yönelimli programlamada mümkün olduğu kadar problemleri parçalara ayırmak (ki buna modülerleştirmek denir) bizim işimizi çok kolaylaştırır. Ne gibi? Uygulamayı geliştirirken yapacağımız çalışmalarda, hata yakalamada, programımızı tak çıkar haline getirmede, kodun daha düzenli ve okunaklı olması gibi avantajlar sağlar. Ama en önemli kullanılma sebebi; classlar, instanceların yani kendinden türetilecek olan nesnelerin bir şablonu görevi görürler. Özetle classlar nesnelerin şablonudur.
Class Inheritance Nedir?
JavaScript’te class inheritance, bir classın başka bir classtan türetilmesini ifade eder. Yani bir classın başka bir class özelliklerini ve davranışlarını miras almasını ve böylece kodumuzun yeniden kullanılabilirliğini artırmasını sağlar. Class inheritance extends keywordü ile gerçekleştirilir. Basit bir örnek verecek olursak eğer;
Yukarıdaki örneğe baktığımız zaman zaten Person isminde bir classımız var. Şimdi 13. satırda teorik olarak daha özellikli olabilecek bir class daha düşünerek Boss isminde bir class tanımlıyoruz. Bu Boss classı normal Person classına ait olan tüm özellikleri içerecektir. Boss’un da name, surname, ve age özellikleri vardır sonuçta. Yani Person classındaki tüm özelliklerin Boss classında da olmasını istiyoruz kısaca. O nedenle extends dedikten sonra hangi classtan inherit edecekse o classı (Person) yazıyoruz ve son olarak classa ait süslü parantezleri ekledik. Daha sonra 15. satırda creed isminde bir person nesnesi, 16. satırda da micheal isminde bir boss nesnesi instantiate ettik. Şimdi bu iki nesneyi ekrana yazdırıp biraz da console üzerinden inceleyelim.
Biz Boss classında age, name ve surname özellikleri yazmadık ama her ikisi de aynı özelliklere sahip. Neden? Çünkü Boss classı Person classını extends ediyor. Şimdilik genişlettiği yok ancak teorik olarak o işi yaptığını varsayalım. Yukarıdaki örneğe bakacak olursak person nesnesinin prototype’ına baktığımızda Object, Object’e baktığımızda ise içinde consturctor olarak person ve fullName metodu var. Ancak boss nesnesine baktığımızda prototype’ı person. Person’ın prototype’ına baktığımızda ise Object. Object’in içine baktığımızda constructor olarak person ve fullName metodunu tekrar görüyoruz. Yukarıdaki durumu şu şekilde düşünebiliriz;
Object + (name, surname, age) → Person
Object’e name, surname ve age gibi özellikleri ekliyoruz bu bize Person classını oluşturuyor.
(Object + (name, surname, age)) Person → Boss
Bu defa tekrar name, surname ve age özelliklerini eklemiyoruz. Zaten yukarıda o özellikleri kullanarak bir Person oluşturduk artık Person üzerinden giderek bir Boss oluşturuyoruz. Boss classında herhangi bir ek özellik olmadığı için tüm özelliklerini Person’dan almış gibi düşünebiliriz.
Ee iyi de biz Boss classını Person classından extend ettik ama kendine ait hiçbir özellik yazmadık bu saçma değil mi? Evet saçma, yukarıdaki gibi bir kullanım görmeyiz zaten. Sadece bir class diğerini inherit ettiğinde neler olduğunu daha net bir şekilde görelim diye böyle bir şey yaptım.
Bu arada yeri gelmişken Boss classı Subclass veya Child olarak isimlendirilir. Person classı ise Superclass veya Parent olarak da tanımlanır.
Şimdi de boss classını person class’ından extend edip kendine ait özellikler vererek bir örnek yapalım.
Yukarıdaki örneği incelediğimizde 13. satıra bakacak olursak boss class’ı person class’ını extend ediyor. Yani person class’ındaki tüm özellikleri alıyor. Daha sonra boss class’ının kendine ait bir constructor fonksiyosununu yazıyoruz. Name, surname, age ve bir de extra olarak job isminde bir özelliğinin olmasını istiyoruz. 15. satıra baktığımızda super sayesinde, gelen name, surname ve age parametrelerini super class’ından yani person class’ından almasını sağlıyoruz. Ayrıca ek olarak da job özelliğini this’e bağlıyoruz. Yani kısaca senin dört özelliğin var bunların üç tanesini parent class’ından al, job da zaten kendine ait olan bir özellik. Verdiğimiz bu dört özelliğin haricinde bir de say metodumuz var gördüğünüz gibi. Bu sayede boss class’ını yeni özelliklerle beraber person class’ından extend etmiş olduk. 25. satırda nesne oluştururken dördüncü parametre olarak Boss değerini verdik, buna dikkat edelim. Eğer herhangi bi değer vermeseydik undefined atanırdı.
Sağ taraftaki console ekranına baktığımız zaman her birinin kendine ait özelliği var. Şimdi boss’un prototype’ına baktığımızda person, yukarıdaki person’ın prototype’ına baktığımızda Object. Neden? Çünkü boss class’ı person class’ını extend ediyor person class’ı neyi extend ediyor? Hiçbir şeyi o yüzden core Object’i gösterir. Şimdi boss’un prototype’ına baktığımızda say metodumuzun da burada olduğunu görüyoruz. Person class’ını ele alacak olursak orada yazdığımız fullName metodu da prototype’ın içinde. Yani subclass’ta oluşturulan bir metot prototype’ına yerleşir diyebiliriz.
Yukarıdaki ok ile yaptığımız anoloji ile ifade edecek olursak şöyle diyebiliriz;
Object + (name, surname, age, fullName()) →Person
Person + (job, say()) → Boss
Yukarıdaki örnekte 30. satıra baktığımızda “Thats what she said” çıktısı alıyoruz bu gayet beklediğimiz bir sonuç zaten. 32. satıra baktığımızda ise hata alıyoruz. Çünkü say metodu boss’a ait bir metottur, boss class’ı person class’ındaki metotları kullanabilir ancak tam tersi bir akış söz konusu değildir.
Evet arkadaşlar bu yazıda nesne yönelimi programlamanın olmazsa olmazı classlardan, classların nesne ile olan ilişkisinden, inheritance’tan ve bunlarla beraber prototype’tan elimden geldiği kadar sade bir şekilde bahsetmeye çalıştım. Umarım faydalı olmuştur, iyi çalışmalar.
Referanslar;
1)Arin Yazılım
2)JavaScript MDN
3)JavaScript Info