Menu

JavaScript Class: Constructor, Method ve new

JavaScript'te class gerçekte nasıl çalışıyor? Constructor, metotlar, instance field'lar, getter/setter ve new anahtar kelimesinin arkasındaki mantık.

Class, Nesneler İçin Bir Şablondur

JavaScript'te bir class, belirli türdeki nesnelerin yapısını ve davranışını tanımlar. Şablonu bir kez yazarsın, sonra ondan istediğin kadar örnek (instance) üretirsin. Her örneğin kendi verisi olur ama hepsi aynı metotları paylaşır.

Temel yapı şöyle görünür:

index.js
Output
Click Run to see the output here.

class User { ... } sınıfın şablonunu tanımlar. new User(...) ise bu şablondan bir örnek (instance) üretir. Her örneğin kendine ait name ve email değerleri olur, ama greet metodu sınıfta tek bir yerde tanımlıdır ve tüm örnekler onu paylaşır.

İki örnek, iki ayrı veri kümesi, tek bir metot kümesi. İşin özü bu kadar.

constructor ile Her Örneği Hazırlamak

constructor, her örnek için yalnızca bir kez çalışan özel bir metottur; new ile yeni bir nesne oluşturulduğu anda devreye girer. Görevi, taze nesneyi başlangıç durumuna getirmektir — genelde de gelen argümanları this üzerine kopyalayarak:

index.js
Output
Click Run to see the output here.

this, constructor içinde o an yaratılmakta olan yeni nesneyi temsil eder. this.x = x yazdığında, x değerini o spesifik nesneye iliştirmiş olursun. Her new Point(...) çağrısı kendi this'ine sahiptir; yani kendi x ve y değerleri olur.

Eğer constructor yazmazsan, JavaScript sana boş bir tanesini otomatik olarak sağlar. Yani constructor'ı yalnızca gerçekten yapılacak bir hazırlık işin varsa yazman gerekir.

new Anahtar Kelimesi Neden Şart?

Bir class'ı new olmadan çağırmak hata fırlatır:

const p = Point(3, 4);
// TypeError: Class constructor Point cannot be invoked without 'new'

Bu, bilinçli bir tasarım tercihi. new anahtar kelimesi sırasıyla dört iş yapar:

  1. Boş, yeni bir nesne oluşturur.
  2. Bu nesneyi class'ın prototype'ına bağlar (metotlar orada durur).
  3. constructor'ı, this yeni nesneye bağlı olacak şekilde çalıştırır.
  4. Yeni nesneyi döndürür.

new olmadan bunların hiçbiri gerçekleşmez. Class bu kuralı zorunlu kıldığı için yanlışlıkla unutma şansın yok — class öncesi dönemde new yazmayı unutmak sessiz sedasız global nesneyi bozabiliyordu, şimdiki hali gerçek bir ilerleme.

Metotlar Ortak, Alanlar Örneğe Özel

Class gövdesinde tanımlanan metotlar prototype üzerinde yaşar — tüm örneklerin paylaştığı tek bir kopya vardır. Örnek alanları (yani this'e atadığın her şey) ise örneğe özeldir; her seferinde ayrı birer kopya oluşur.

index.js
Output
Click Run to see the output here.

İki instance'ın da kendi count değeri var, dolayısıyla birini artırmak diğerini etkilemiyor. Ama a.increment ile b.increment aslında birebir aynı fonksiyon — prototype üzerinde tek bir yerde tutuluyor, instance üzerinden çağırdığında oradan bulunup çalıştırılıyor. JavaScript class yapısının ucuza ölçeklenmesinin sebebi de bu: bin tane instance oluştursan bile her metodun bin kopyası üretilmiyor.

Class Field'ları

Instance field'larını constructor'ın dışında, class gövdesinin en üstünde de tanımlayabilirsin:

index.js
Output
Click Run to see the output here.

Alan tanımlamaları (field declarations), constructor gövdesinden önce çalışır — sanki constructor'ın en üstüne yazılmış gibi. Başlangıç değeri constructor argümanlarına bağlı değilse çok işe yarar; this.count = 0; this.step = 1; gibi satırlarla constructor'ı kalabalıklaştırmaktan çok daha temiz bir yaklaşım.

Ama değerler argümanlara bağlıysa, atamayı constructor içinde tutmak daha mantıklı — zaten argümanlar orada kapsam içinde.

Getter ve Setter Kullanımı

Getter ya da setter görünüşte bir metottur ama davranışı bir property erişimi gibidir. Parantez kullanmadan okur veya atama yaparsın; metot arka planda çalışır:

index.js
Output
Click Run to see the output here.

Çağrıların nasıl yazıldığına dikkat edin: t.fahrenheit (parantezsiz) getter'ı okur, t.fahrenheit = 100 ise setter'ı tetikler. Dışarıdan bakıldığında fahrenheit sıradan bir property gibi görünür ama aslında her seferinde celsius üzerinden anlık olarak hesaplanır.

Getter'lar türetilmiş değerler için çok kullanışlıdır. Setter'lar ise atama sırasında değeri doğrulamak ya da normalize etmek için birebirdir. Yine de bunları suistimal etmeyin — maliyetli bir getter yazarsanız, kodu okuyan biri "property'ye erişiyorum" derken arka planda ciddi bir iş döndüğünü görünce şaşırır.

Metot kısa yazımı, hesaplanan isimler ve this

Bir class içindeki metot tanımları kısa yazım (shorthand) biçimindedir — ne function anahtar kelimesi vardır, ne de isim ile gövde arasında : işareti:

index.js
Output
Click Run to see the output here.

add metodunun this döndürmesi, method chaining (zincirleme metot çağrısı) yapabilmemizi sağlıyor — her çağrı aynı instance'ı geri verdiği için bir sonraki metot onun üzerinde çalışabiliyor.

Ama dikkat edilmesi gereken bir nokta var: metotlar ait oldukları instance'a otomatik olarak bağlanmıyor. Bir metodu alıp tek başına çağırırsanız, this referansı kaybolur:

index.js
Output
Click Run to see the output here.

g.hello() çağrısı çalışır çünkü . operatörü this değerini otomatik olarak sağlar. Ama fn() şeklinde tek başına çağırdığında bu bağ kopar. Eğer metodu nesneden ayrı bir şekilde, önceden bağlanmış olarak kullanman gerekiyorsa (event handler'larda sık karşılaşılan bir durum), ya constructor içinde bind kullan ya da arrow function'lı class field tanımla: hello = () => \Hi, ${this.name}`;`.

Küçük Bir Çalışan Örnek

Şimdi parçaları bir araya getirelim — field'lar, constructor, metotlar ve bir getter:

index.js
Output
Click Run to see the output here.

Bir bakışta anlaşılıyor: sınıf, bir BankAccount nesnesinin ne olduğunu ve neler yapabildiğini net bir şekilde anlatıyor.

Aslında Sınıflar Birer Fonksiyondur

Kafaya kazınması gereken bir nokta var: class büyük ölçüde söz dizimsel bir şekerden ibaret. Perde arkasında her sınıf aslında bir fonksiyondur — daha doğrusu bir constructor fonksiyonu — ve metotları da ClassName.prototype üzerinde yaşar:

index.js
Output
Click Run to see the output here.

typeof User sonucu "function" döner. greet metodu ise User.prototype üzerinde yaşar. Örnekler (instances), greet'e prototip zinciri üzerinden erişir — yani dilin ilk gününden beri var olan aynı mekanizma devrede. Class sözdizimi aslında bu kurulumu temiz bir şekilde yapmanın kısayolu.

Bu zihinsel model ilerde çok işinize yarayacak: kalıtım, instanceof ve prototip zincirinde hata ayıklama — hepsi, bir class'ın aslında prototipine metotlar iliştirilmiş bir fonksiyon olduğunu hatırladığınızda çok daha anlamlı hale geliyor.

Sırada: Kalıtım (Inheritance)

Şimdiye kadar her class tek başına duruyordu. Ama gerçek projelerde çoğu zaman class hiyerarşileri kurarsınız — Animal'ın bir türü olan Dog, ya da User'ın bir türü olan AdminUser gibi. Bu işi extends ve super anahtar kelimeleri hallediyor; sırada onlar var.

Sıkça Sorulan Sorular

JavaScript'te class nasıl oluşturulur?

Önce class anahtar kelimesi ve bir isim yazıyorsunuz, ardından süslü parantez içinde bir constructor metodu ve istediğiniz diğer metotları tanımlıyorsunuz. Instance oluşturmak için de new ClassName(...) kullanıyorsunuz. Örnek: class User { constructor(name) { this.name = name; } } ve ardından new User('Ada').

JavaScript class içindeki constructor ne işe yarar?

constructor, siz new ClassName(...) çağırdığınızda bir kez çalışır. Görevi yeni instance'ı hazırlamaktır — genelde gelen argümanları this üzerine instance property olarak atamak için kullanılır. Siz yazmazsanız JavaScript arka planda boş bir varsayılan constructor oluşturur.

JavaScript'te class ile function arasındaki fark nedir?

Aslına bakarsanız class da bir function'dır — daha doğrusu metotları prototype'a bağlanmış bir constructor function. class anahtar kelimesi büyük ölçüde syntactic sugar ama birkaç ekstrası var: new olmadan çağrılmaya izin vermez, extends çok daha temiz çalışır ve metotlar non-enumerable olarak tanımlanır. Yeni kod yazarken elle constructor function yazmak yerine class kullanmanız daha mantıklı.

Coddy ile kodlamayı öğren

BAŞLA