Static Üyeler Sınıfa Aittir, Örneğe Değil
Bir sınıfta yazdığınız metotların çoğu belirli bir örnek üzerinde çalışır — örneğin belirli bir user ya da belirli bir circle. Ama static üyeler farklıdır. Bunlar doğrudan sınıfın kendisine aittir. Yani bir örnek üzerinden değil, sınıf adıyla çağırırsınız.
double, MathUtils üzerinde yaşıyor; örneklerinin üzerinde değil. Örnek oluşturmak da işe yaramıyor — m.double sonucu undefined. Bu, normal metotların tam tersi bir durum: onlar örneklerin üzerinde (teknik olarak prototype üzerinde) yaşar ve sınıfın kendisinden görünmezler.
Kafamızda şöyle bir model oluşturalım: class anahtar kelimesi aslında iki ayrı küme oluşturuyor — new MathUtils() ile kullanılan örnek (instance) metotları ve doğrudan MathUtils üzerinden çağrılan statik (static) metotlar. static anahtar kelimesi ise bir üyenin hangi kovaya düşeceğini belirliyor.
Klasik kullanım: Factory metotları
JavaScript'te static metot yazmanın en yaygın sebebi alternatif constructor tanımlamaktır. Asıl constructor kendi parametrelerini alır, ama çoğu zaman nesneyi başka yollarla da oluşturmak istersin — JSON'dan, veritabanı satırından ya da bir URL'den mesela.
fromJSON bir user kullanmıyor — bir user üretiyor. İşte tam da bu noktada static metot tam oturur. Alternatif olarak ortalıkta dolaşan bir parseUser fonksiyonu yazabilirdin ama bunu sınıfın üzerinde tutmak, ilgili davranışları bir arada tutar ve çağrı yerinde niyetini net biçimde ortaya koyar.
Statik Özellikler (Static Properties)
Veriyi de doğrudan sınıfın kendisine iliştirebilirsin:
Circle.PI her daire için ortaktır — her örneğe kopyalanmaz, sınıfın üzerinde duran bir sabittir. Instance metotlarının içinde bu sabite this üzerinden değil, sınıf adıyla (Circle.PI) erişirsiniz.
Statik özellikler; yapılandırma ayarları, örnekler arasında paylaşılan cache'ler, sayaçlar ve sınıf seviyesindeki sabitler için oldukça kullanışlıdır.
Statik Metot İçinde this Sınıfın Kendisidir
Normal bir metodun içinde this o örneği (instance) temsil eder. Ama statik bir metodun içinde this, doğrudan sınıfın kendisine işaret eder:
increment içindeki this.count, aslında Counter.count demek oluyor. İlk bakışta kafa karıştırıcı gelebilir ama static metotların kalıtımla düzgün çalışmasını sağlayan şey tam olarak bu — this, metodu tanımlayan sınıfa değil, metodu çağırdığın sınıfa işaret eder.
JavaScript'te Static Metot Kalıtımı
Static metotlar alt sınıflara miras kalır. Ve this metodun çağrıldığı sınıfı gösterdiği için, factory metotlar otomatik olarak doğru alt sınıfı üretir:
Animal.create içinde new this(name) kullanılıyor. Dog.create("Rex") çağrıldığında this artık Dog olduğu için new this(name) bir Dog örneği üretir. Oraya new Animal(name) yazsaydık her seferinde Animal dönerdi ve kalıp bozulurdu. İşte tam da bu yüzden static metotlarda this, sınıfın kendisine işaret eder.
Static ve Instance Karşılaştırması: Uygulamalı Örnek
Aynı mantığı iki farklı yaklaşımla kurguladığımızda şöyle görünüyor:
İkisi de aynı hesabı yapıyor. Örnek (instance) sürümü veriyi this.celsius üzerinden okuyor; statik sürüm ise girdisini parametre olarak alıyor. Eğer işlem "bu nesnenin yaptığı bir şey" ise instance metodunu; "sınıfın, kendisine verilen girdilerle nasıl hesaplayacağını bildiği bir şey" ise static metodu tercih et.
Kurulum için static block kullanımı
Bazen bir statik özelliği ilklendirmek tek bir ifadeyle yapılamaz; döngü, koşul veya birbirine bağlı birden fazla değer gerekebilir. İşte static blokları tam da bunun için var:
static { ... } bloğu, sınıf tanımlandığı anda bir kez çalışır. Blok içinde this, sınıfın kendisine karşılık gelir. Birden fazla adımdan oluşan kurulumlar için idealdir; tek satırlık bir atama yapacaksan düz bir static alan çok daha okunaklı durur.
Private Static Üyeler
Static alanlar da # ön eki ile private hâle getirilebilir. Bu şekilde tanımladığın üyelere yalnızca sınıfın içinden erişebilirsin:
#nextId sınıfın içinde kilitli kalıyor. Dışarıdaki kod IdGenerator.next() çağırabilir ama sayaca dokunamaz, sıfırlayamaz. Private alanların kendi sayfası birazdan geliyor; şimdilik static ile # kombinasyonunun sorunsuz çalıştığını bilmek yeterli.
static Kullanmamanız Gereken Durumlar
JavaScript static metotlar yardımcı fonksiyonları gruplamak için güzel bir yol, ama her utility'yi sınıfa çevirmek için bahane değil. Elinizde birbirinden bağımsız fonksiyonlarla dolu bir dosya varsa, fonksiyonları olduğu gibi export edin — sırf isim alanı oluşturmak için hepsini statik metotlardan oluşan bir sınıfa sarmayın. Modül zaten bu işi yapıyor, hem de daha temiz şekilde.
Şu durumlarda static'e başvurun:
- Fonksiyon gerçekten sınıfa ait (o tip için factory, dönüştürücü ya da validator).
- Sınıfın tüm örnekleri arasında paylaşılacak bir state'e ihtiyacınız var.
- Bir alt sınıf davranışı override etmek veya miras almak isteyebilir.
Bunların dışında, sade bir fonksiyon daha basit bir çözümdür.
Sırada: Private Alanlar
#nextId'yi kısaca gördünüz — bu JavaScript'in private alan sözdizimi. Hem instance hem de static üyelerde çalışır ve bir sınıfın implementasyon detaylarını gizlemenin modern yoludur. Bir sonraki konu tam olarak bu.
Sıkça Sorulan Sorular
JavaScript'te statik metot nedir?
Statik metot, sınıfın örneklerine (instance) değil, doğrudan sınıfın kendisine ait bir metottur. static anahtar kelimesiyle tanımlanır ve sınıf üzerinden çağrılır: MyClass.doThing(). Örnekler üzerinden this.doThing() şeklinde erişemezsiniz — yalnızca sınıf üzerinden çalışır.
Statik metot mu, instance metot mu kullanmalıyım?
Eğer fonksiyon sınıfla ilgili ama belirli bir örneğin verisini okuyup değiştirmesi gerekmiyorsa statik metot iyi bir seçimdir. Tipik örnekler: User.fromJSON(...) gibi factory metotlar, Math.max gibi yardımcı fonksiyonlar ve sınıfı bir namespace gibi kullanan sabitler. Ama this ile örneğin verisine erişmeniz gerekiyorsa o zaman instance metot yazmalısınız.
Statik metotlar instance özelliklerine erişebilir mi?
Doğrudan erişemez. Statik metot içinde this, bir örneği değil sınıfın kendisini işaret eder; dolayısıyla this.name yazdığınızda instance alanını değil statik bir özelliği okursunuz. Örneğe ait veriye ihtiyaç duyuyorsanız örneği parametre olarak geçirmeniz gerekir: static summarize(user) { return user.name; }.
JavaScript'te statik metotlar miras alınır mı?
Evet. Bir alt sınıf extends ile başka bir sınıfı genişlettiğinde, üst sınıfın statik metotları alt sınıfta da kullanılabilir hale gelir. Statik metot içinde this, metodu hangi sınıf üzerinden çağırdıysanız o sınıfı gösterir — statik factory metotların alt sınıflarda da doğru çalışmasını sağlayan şey tam olarak budur.