7 Mayıs 2016 Cumartesi

Javascript'de Sınıflar

Merhaba Webkolog Dostları!

Bugün, JavaScript'in modern yüzünün önemli bir parçası olan Sınıfları (Classes) konuşacağız. ES6 (ECMAScript 2015) ile hayatımıza giren sınıflar, nesne yönelimli programlama (OOP) kavramlarını JavaScript'e daha tanıdık ve anlaşılır bir şekilde taşımıştır. Eğer kodunuzu daha modüler, yeniden kullanılabilir ve okunabilir hale getirmek istiyorsanız, sınıflar kesinlikle öğrenmeniz gereken bir konudur. Haydi, bu yapısal harikalığı keşfedelim!


Sınıf Nedir ve Neden Kullanırız?

Geleneksel olarak JavaScript, prototip tabanlı bir dildir. Yani nesneler, başka nesnelerden "türetilerek" oluşturulur. Ancak ES6 ile gelen class anahtar kelimesi, diğer nesne yönelimli dillerdeki (Java, C++ gibi) sınıf kavramına daha yakın bir sözdizimi sunar. Aslında arka planda hala prototip mekanizması çalışsa da, sınıflar bize daha temiz ve anlaşılır bir "blueprint" (taslak) oluşturma imkanı tanır.

Sınıfları kullanma nedenlerimiz:

  • Kod Düzenliliği: Benzer özelliklere ve davranışlara sahip nesneleri tek bir çatı altında toplar.
  • Yeniden Kullanılabilirlik: Bir sınıf tanımladıktan sonra, ondan istediğiniz kadar nesne (instance) üretebilirsiniz.
  • Mirası (Inheritance): Var olan sınıflardan yeni sınıflar türeterek kod tekrarını azaltır ve hiyerarşik yapılar oluşturmayı kolaylaştırır.
  • Okunabilirlik: Özellikle OOP geçmişi olan geliştiriciler için kodun anlaşılmasını kolaylaştırır.

Sınıf Tanımlama ve Nesne Oluşturma

Bir sınıf, genellikle büyük harfle başlayan (PascalCase) bir isimle tanımlanır. Sınıfın temel yapısını constructor metodu oluşturur.

1. Temel Sınıf Yapısı

    // Sınıf tanımlama
    class UzayMekigi {
        // constructor: Sınıftan yeni bir nesne oluşturulduğunda ilk çalışan metottur.
        // Genellikle nesnenin başlangıç özelliklerini (property) tanımlamak için kullanılır.
        constructor(hedefGezegen) {
            this.hedefGezegen = hedefGezegen; // this anahtar kelimesi, o anki nesneyi temsil eder.
        }

        // Metot tanımlama: Sınıfa ait davranışları belirler
        firlatmaYap() {
            console.log(`${this.hedefGezegen} gezegenine doğru fırlatılıyor...`);
        }
    }

    // Sınıftan yeni bir nesne (instance) oluşturma
    const zeus = new UzayMekigi('Jüpiter');
    const apollo = new UzayMekigi('Ay');

    console.log(zeus.hedefGezegen);   // Jüpiter
    zeus.firlatmaYap();               // Jüpiter gezegenine doğru fırlatılıyor...

    console.log(apollo.hedefGezegen); // Ay
    apollo.firlatmaYap();             // Ay gezegenine doğru fırlatılıyor...

Getter ve Setter Metotları

Getter ve Setter metotları, bir sınıfın özelliklerine dışarıdan doğrudan erişimi kontrol etmenizi sağlar. Bu, veri kapsülleme (encapsulation) için önemlidir, yani bir özelliğin değerini okurken veya değiştirirken belirli mantıklar uygulayabilirsiniz.

  • get: Bir özelliğin değerini okumak için kullanılır.
  • set: Bir özelliğin değerini değiştirmek için kullanılır. Genellikle atama öncesi doğrulama gibi işlemler yapılır.

    class Kitap {
        constructor(yazar) {
            this._yazar = yazar; // Özelliğin başına '_' koymak, genellikle private olduğunu belirtir (bir kuraldır, zorunluluk değil)
        }

        // Getter metodu
        get yazarAdi() {
            console.log("Yazar adı isteniyor...");
            return this._yazar.toUpperCase(); // Yazar adını büyük harflerle döndür
        }

        // Setter metodu
        set yazarAdi(yeniYazar) {
            if (yeniYazar.length < 3) {
                console.warn("Yazar adı en az 3 karakter olmalıdır!");
            } else {
                this._yazar = yeniYazar;
                console.log("Yazar adı güncellendi.");
            }
        }
    }

    const myBook = new Kitap('anonim');
    console.log(myBook.yazarAdi); // Yazar adı isteniyor... \n ANONIM

    myBook.yazarAdi = 'f';    // Yazar adı en az 3 karakter olmalıdır!
    myBook.yazarAdi = 'Can Yılmaz';
    console.log(myBook.yazarAdi); // Yazar adı isteniyor... \n CAN YILMAZ

Statik Metotlar

Statik metotlar, sınıfın kendisiyle ilişkilendirilmiş metotlardır, bir sınıfın nesneleriyle (instance) değil. Bu metotlara sınıf adıyla doğrudan erişilir ve genellikle sınıfın genel yardımcı fonksiyonları olarak kullanılırlar.


    class Nokta {
        constructor(x, y) {
            this.x = x;
            this.y = y;
        }

        // Statik metot: İki nokta arasındaki mesafeyi hesaplar
        static uzaklikHesapla(noktaA, noktaB) {
            const dx = noktaA.x - noktaB.x;
            const dy = noktaA.y - noktaB.y;
            return Math.sqrt(dx * dx + dy * dy); // Pisagor teoremi
        }
    }

    const p1 = new Nokta(0, 0);
    const p2 = new Nokta(3, 4);

    // Statik metodu sınıf adı üzerinden çağırırız
    console.log(Nokta.uzaklikHesapla(p1, p2)); // 5 (Math.hypot(3, 4) ile aynıdır)

    // p1.uzaklikHesapla(p2); // Hata! Statik metotlar nesne üzerinden çağırılamaz.

Mirası (Inheritance) ve extends Anahtar Kelimesi

Mirası, bir sınıfın (alt sınıf veya türetilmiş sınıf) başka bir sınıfın (üst sınıf veya temel sınıf) özelliklerini ve metotlarını devralmasını sağlar. Bu, kod tekrarını önler ve daha hiyerarşik bir yapı oluşturur. JavaScript'te extends anahtar kelimesi ile mirası sağlanır.


    // Üst sınıf (Parent Class)
    class Hayvan {
        constructor(isim) {
            this.isim = isim;
        }
        sesCikar() {
            console.log(this.isim + ' bir ses çıkarıyor.');
        }
    }

    // Alt sınıf (Child Class) - Hayvan sınıfından miras alır
    class Kopek extends Hayvan {
        constructor(isim, cins) {
            super(isim); // super() üst sınıfın constructor'ını çağırır
            this.cins = cins;
        }
        havla() {
            console.log(this.isim + ' havlıyor: Hav hav!');
        }
        // Üst sınıftaki metodu geçersiz kılma (Override)
        sesCikar() {
            console.log(this.isim + ' tatlı tatlı havlıyor.');
        }
    }

    class Kedi extends Hayvan {
        constructor(isim) {
            super(isim);
        }
        miyavla() {
            console.log(this.isim + ' miyavlıyor: Miyav!');
        }
        // Üst sınıftaki metodu çağırıp üzerine ekleme yapma
        sesCikar() {
            super.sesCikar(); // Üst sınıfın sesCikar metodunu çağır
            console.log(this.isim + ' nazikçe miyavladı.');
        }
    }

    const karabas = new Kopek('Karabaş', 'Golden');
    karabas.sesCikar(); // Karabaş tatlı tatlı havlıyor. (Geçersiz kılınan metot)
    karabas.havla();    // Karabaş havlıyor: Hav hav!
    console.log(karabas.cins); // Golden

    const pamuk = new Kedi('Pamuk');
    pamuk.sesCikar(); // Pamuk bir ses çıkarıyor. \n Pamuk nazikçe miyavladı.
    pamuk.miyavla(); // Pamuk miyavlıyor: Miyav!

Modüller: import ve export (ES6+)

Büyük projelerde kodumuzu daha küçük, yönetilebilir dosyalara bölmek isteriz. JavaScript modülleri, bu amaca hizmet eder. export ile bir dosyadan fonksiyonları, değişkenleri veya sınıfları dışarıya açarız; import ile de başka bir dosyada bunları kullanırız.

Export Yöntemleri
  • Named Export (İsimlendirilmiş Dışa Aktarma): Birden fazla öğeyi dışa aktarmak için kullanılır.
    
                // dosya: utils.js
                export const PI = 3.14;
                export function topla(a, b) {
                    return a + b;
                }
                export class HesapMakinesi {
                    // ...
                }
            
  • Default Export (Varsayılan Dışa Aktarma): Her dosyadan yalnızca bir tane default export olabilir. Dosyanın ana öğesini dışa aktarmak için kullanılır.
    
                // dosya: myModule.js
                const benimSablonum = {
                    // ...
                };
                export default benimSablonum;
    
                // veya doğrudan fonksiyon/sınıf olarak
                export default function cikar(a, b) {
                    return a - b;
                }
            
Import Yöntemleri
  • Named Import: İsimlendirilmiş dışa aktarılan öğeleri süslü parantezler içinde aynı isimleriyle içeri aktarırız.
    
                // dosya: app.js
                import { PI, topla } from './utils.js'; // uzantı önemli!
                import { HesapMakinesi } from './utils.js';
    
                console.log(PI);        // 3.14
                console.log(topla(5, 7)); // 12
            
  • Default Import: Varsayılan dışa aktarılan öğeyi istediğimiz bir isimle içeri aktarırız (süslü parantez kullanılmaz).
    
                // dosya: app.js
                import BenimNesnem from './myModule.js'; // İsim farklı olabilir
                import cikarmaIslemi from './cikar.js'; // cikar.js dosyasındaki default export'u kullanır
    
                // BenimNesnem'i kullan
                console.log(cikarmaIslemi(10, 3)); // 7
            
  • Tümünü İçeri Aktarma (Wildcard Import): Bir modüldeki tüm dışa aktarılan öğeleri tek bir obje olarak içeri aktarırız.
    
                // dosya: app.js
                import * as utils from './utils.js';
    
                console.log(utils.PI);
                console.log(utils.topla(2, 2));
                const calc = new utils.HesapMakinesi();
            

Modüllerin HTML'de Kullanımı: Modül olarak kullanılan JavaScript dosyalarını HTML'ye eklerken <script type="module"></script> kullanmayı unutmayın.


    <!-- index.html -->
    <script type="module" src="app.js"></script>

Sonuç

JavaScript sınıfları ve modülleri, kodunuzu organize etmek, tekrar kullanılabilir hale getirmek ve büyük ölçekli uygulamalar geliştirmek için modern ve güçlü araçlardır. Nesne yönelimli programlama prensiplerini uygulayarak daha temiz, daha anlaşılır ve daha sürdürülebilir kodlar yazabilirsiniz. Özellikle ekip çalışmalarında ve karmaşık projelerde bu yapılar, iş akışınızı inanılmaz derecede kolaylaştıracaktır.

Bu konularda pratik yapmayı sürdürün, kendi sınıflarınızı ve modüllerinizi oluşturarak bilginizi pekiştirin. Unutmayın, iyi kodlama alışkanlıkları zamanla gelişir!

Webkolog'u takipte kalın!

Hepinize bol kodlu ve başarılı projeler dilerim!

0 yorum:

Yorum Gönder