JavaScript’te Class Kavramı — 1

Fatih Cihan
6 min readOct 25, 2023

--

Herkese merhaba, bu yazıda sizlere class kavramından bahsetmeye çalışacağım. Daha öncesinde JavaScript’tin nesne yönelimli programlamayı nesne üzerinden nasıl ele aldığını prototype kavramıyla bahsetmiştik. İsteyenler yazıya buradan ulaşabilir. Bu dersimizde ise OOP’nin olmazsa olmaz kavramlarından biri olan classlara giriş yapacağız. Neden classlara ihtiyaç duyuldu? Prototype’ta ne gibi eksiklikler vardı onları inceleyeceğiz.

Biz önceden nesnemizi oluşturmak için, nesne oluşturma yöntemlerinden biri olan constructor fonksiyonu kullanıyorduk. Şimdi bu nereden çıktı diyecek olursanız classların daha iyi anlaşılması için biraz geriye gitmenin iyi olacağını düşünüyorum.

Görmüş olduğunuz gibi constructor fonksiyondan faydalanarak nesnelerimizi oluşturduk burada herhangi bir yenilik yok. Bizim burada daha çok odaklanmamız gereken 5. satır. Çünkü burada function keywordü ile fonksiyon oluşturuluyor yani biz micheal nesnesini oluşturduğumuzda da dwight nesnesi oluşturduğumuzda da bu fullName fonksiyonunu çalıştırıyoruz. Sonuç olarak biz her bir nesne oluştururken farklı fonksiyonlar çalıştırıyoruz ve farklı fonksiyonlar çalıştırırken farklı başka nesneler de oluşturuyoruz işte bu durum da gereğinden fazla bellek kullanıma neden olur bu da bizim istemediğimiz bir durumdur. Bu problemi çözebiliriz elbette hatta çözelim.

Yukarıdaki örneğe bakacak olursak fullName fonksiyonunu constructor fonksiyonun içinde oluşturma artık 8. satırda global olarak oluşturduğum fullName fonksiyonunu çağır diyoruz. Bu sayede micheal nesnesi de dwight nesnesi de aynı fonksiyona yani globalde yazdığımız fullName fonksiyonunu çağırıyor. Biraz önceki problemden kurtulduk. Yalnız bu durumda da şöyle düşünebiliriz biz burada bir tane fonksiyon çalıştırdık peki 100 tane farklı fonksiyon olsaydı ? O zaman 100 tane fonksiyonun hepsini de globalde ayrı ayrı oluşturmaya çalışacağız. Bu da zamanla globalde kullandığımız fonksiyonların çok fazla olmasına neden olur. Biz böyle bir durumdan ziyade mümkün olduğu kadar fonksiyonların kendi işlevlerini yapmasını isteriz ancak kendi işlevini yapmasını istediğimiz fonksiyon ana dosyamızda bağımsız bir şekilde olduğu zaman hem güvenlik açısından hem de performans açısından ciddi zararlar verebilir.

Yukarıdaki yöntem de başka bir problem çıkardı peki ne yapabiliriz ? Ayrı ayrı global bir fonksiyon şeklinde değil de ilgili constructor fonksiyonumza prototype olarak ekleyebiliriz. Bu durumu da biraz inceleyelim.

Evet yukarıdaki örneğe baktığımızda fullName fonksiyonunu görmüş olduğunuz gibi proto nesnesinin içine aldık. Ancak JavaScript’te referans veri tipleri kullanıldığında prototype ile ilgili bir takım problemlere sebep olabiliyor. Ne demek istiyorum? Bunu bir örnekle açıklamak daha iyi olabilir.

Yukarıdaki örneğe baktığımızda 11. satırda person’ın prototype’ına friends isminde yeni bir özellik (array) ekliyoruz. 16. ve 17. satırda micheal ve dwight nesnelerini ekrana yazdırdığımızda görüldüğü gibi her ikisinin protolarında friends özelliği var. Şimdi micheal nesnesine yeni bir arkadaş ekleyelim o zaman.

Evet yukarıdaki örneğe baktığımızda 16. satırda micheal’ın arkadaşlarına jim’i ekledik. 18. satıra baktığımızda artık micheal’ın arkadaşları, Pam Angela ve Jim oldu. Ancak 19. satıra baktığımızda dwight’ın arkadaşları da aynı şekilde değişti. Biz bunun böyle olmasını istemeyiz. Peki neden böyle oldu? Baktığımız zaman friends özelliği prototype’tan geliyor. Biz prototype’ı değiştirirsek her bir instance için o nesnenin prototype’tan gelen özelliği değişiyor. Özetle biz her bir instance’ın kendi özelliklerine sahip olmasın isteriz. Biz bu problemi de çözebiliriz aslında friends’i prototype’tan çıkarıp constructor fonksiyonun içine taşırız vs. Ancak gördüğümüz gibi işler giderek karmaşıklaşmaya başlıyor yani iki tane nesne oluşturup bu nesneye birkaç tane özellik vermek istediğimizde bile bu tip sorunlarla karşılaşıyorsak büyük bir projede karşılaşacak problemleri siz düşünün. İşte burada devreye classlar giriyor. Buraya kadar classlara neden ihtiyaç duyduğumuzu göstermeye çalıştım aslında. Şimdi gelelim class kavramına

Class Nedir ?

Class dediğimiz şey özel bir fonksiyondur diyerek bir tanımını yapalım. Şimdi biz yukarıda consturctor function yardımıyla nesne oluşturuyorduk. Artık classlar yardımıyla nesne oluşturmanın zamanı geldi. İkisini karşılaştırmalı olarak inceleyelim.

Yukarıdaki örneğe baktığımızda constructor fonksiyonunu baz alarak bir class oluşturuyoruz. Öncelikle class keywordünü kullanıyoruz daha sonra class ismini (genel kullanım olarak class isimleri büyük harfle başlar) belirtiyoruz. Şimdi 1. satırdaki constructor fonksiyona bakacak olursak parametreler alıyoruz daha sonra o parametreleri ilgili objeye ataması için this keywordünden yararlanıyoruz. Bunun aynısını class oluştururken yapan fonksiyona biz consturctor fonksiyon diyoruz. Yalnız buradaki constructor fonksiyon bir class’ın içindeki metot şeklinde. 9. satırda aynen yukarıda constructor fonksiyonu gibi name, surname ve age parametrelerini alıp fonksiyon scope’larını açarak constructor fonksiyondaki aynı işlemleri gerçekleştiriyoruz. Yani class sayesinde, bir nesne oluştururken constructor fonksiyonu oluşturuyoruz, constructor fonksiyonu haricindeki diğer metotları da ayrı ayrı yazabi1iyoruz.

Şimdi biraz da class içindeki constructor metot hakkında konuşalım. Buradaki constructor metot, nesne oluşumunda otomatik olarak class içerisinde çalışan metottur. 20. satıra bakacak olursak new keywordü ile micheal nesnemizi oluşturduk. Bu new keywordü çalışmaya başladığında sırasıyla şu işlemler gerçekleşir. Önce hafızada micheal nesnesi için bir yer ayrılır, ikinci olarak this keywordü o an oluşturulan nesne (current object) ne ise (bizim örneğimizde micheal) onun yerini alır, üçüncü olarak yaptığı ise constructor metodunu çalıştırır. Şimdi class ile oluşturduğumuz ilgili nesneleri ekrana yazdıralım ve console ortamında biraz daha inceleyelim.

Şimdi yukarıdaki örneğe baktığımızda micheal ve dwight nesnelerini console’a yazdırdık. Burada age, name ve surname propertyleri var ancak fullName metodu yok? İşte o da gördüğümüz gibi prototype’ın içinde. Ayrıca biz burada class kullandık ama prototype’ın aynısı var neden? Çünkü biz kendimiz class kullansak da arkadaki JavaScript Engine ile yapılan işlemlerin tamamı aynı aslında. Bizim burada class ile yaptığımız şey, yalnızca daha sade ve klasik nesne yönelimli yaklaşımın olması yani nesne oluşturmayı daha okunabilir ve yönetilebilir bir hale getiriyor. Peki classlar sayesinde farklı farklı instance’ları değiştirebiliyor muyuz bir de ona bakalım (yukarıdaki friends örneğimize tekrar dönelim)

Yukarıdaki örneğe baktığımızda her iki nesnenin de friends’leri Pam ve Angela burada herhangi bir problem yok. Biz 17. satırda micheal nesnesinin friends arrayine Jim’i ekliyoruz. 19. satırda micheal nesnesinin friends arrayini ekrana yazdırdığımızda doğal olarak Pam, Angela ve Jim’i ekranda görüyoruz. Ancak 20. satıra baktığımızda ise dwight nesnesinin friends arrayini ekrana yazdırdığımızda ise sadece Pam ve Angela’yı görüyoruz. Buradan artık JavaScript classları derken aslında JavaScript classlarının özel birer fonksiyon olduğuna ikna olmuşuzdur. Olmadıysak eğer ispatlayalım.

14. satırda gördüğümüz gibi Person’ın typeof’una baktığımız zaaman function çıktısı alıyoruz. O zaman artık gönül rahatlığıyla JavaScript classlarının aslında özel bir fonksiyon olduğunu söyleyebiliriz. Ee iyi de biz fonksiyonlarda, function declaration ve function expression olarak iki şekilde kullanıyorduk bu durumun aynısı classlar için de geçerli.

Evet arkadaşlar bu yazımda classların daha iyi anlaşılması ve oturması için temel olarak başlangıçtan almak istedim hem bu sayede önceki konuları da tekrar etmiş olduk. Umarım faydalı olmuştur, iyi çalışmalar.

Referanslar;
1)Arin Yazılım
2)JavaScript Info
3)JavaScript MDN

--

--