Bu makalede, JavaScript’in modern dünyasındaki temel yapı taşlarını ve kavramlarını inceleyeceğiz. Fonksiyon türlerinden başlayarak (anonim, arrow, geri çağırma, async/await), closure kavramının derinliklerine inecek ve this
anahtar kelimesinin gizemlerini çözeceğiz. Ardından, JavaScript’in nesne yönelimli programlama (OOP) yaklaşımını, prototip tabanlı miras almayı ve ES6 sınıflarını (class, constructor, extends, super) ele alacağız. Tüm bu teorik bilgileri, pratik bir örnekle pekiştireceğiz: Ürünleri listeleyen ve sepete ekleyen basit bir alışveriş uygulaması geliştireceğiz. Bu yolculukta, JavaScript’in gücünü ve esnekliğini daha iyi anlayacak, kod yazma becerilerinizi bir üst seviyeye taşıyacaksınız. Bu makalede, Javascript’in en can alıcı noktalarını öğrenerek, bilgilerimizi güncelleyeceğiz.
Fonksiyon Türleri ve Closure Kavramı
JavaScript’te fonksiyonlar, “first-class citizen” olarak kabul edilirler, yani diğer veri türleri gibi değişkenlere atanabilir, parametre olarak geçirilebilir ve fonksiyonlardan döndürülebilirler. Bu esneklik, farklı fonksiyon türlerinin ortaya çıkmasını sağlamıştır:
- Anonim Fonksiyonlar: İsmi olmayan fonksiyonlardır. Genellikle bir değişkene atanır veya başka bir fonksiyona parametre olarak geçirilirler.
const topla = function(a, b) { return a + b; };
- Arrow Fonksiyonlar: ES6 ile tanıtılan, daha kısa ve okunaklı bir sözdizimine sahip fonksiyonlardır.
this
bağlamı, arrow fonksiyonlarda farklılık gösterir (lexical scoping).const carp = (a, b) => a * b;
- Geri Çağırma (Callback) Fonksiyonları: Başka bir fonksiyona parametre olarak geçirilen ve o fonksiyonun belirli bir işlem tamamlandığında çağırdığı fonksiyonlardır. Asenkron işlemlerde sıkça kullanılırlar.
setTimeout(() => { console.log("2 saniye geçti"); }, 2000);
- Async/Await: Asenkron işlemleri daha senkron bir şekilde yazmamızı sağlayan ES8 ile gelen anahtar kelimelerdir.
async
ile işaretlenen bir fonksiyon,await
ile bir Promise’in çözümlenmesini bekleyebilir.1234567async function veriGetir() {const response = await fetch('https://api.example.com/data');const data = await response.json();return data;}
Closure, bir fonksiyonun, kendi dışındaki kapsamda (lexical scope) tanımlanan değişkenlere erişebilme yeteneğidir. Bu, fonksiyonun tanımlandığı ortamı “hatırlaması” anlamına gelir. Closure’lar, özel değişkenler oluşturmak, state yönetimi yapmak ve modüler kod yazmak için güçlü bir araçtır.
this
Anahtar Kelimesi
this
anahtar kelimesi, JavaScript’te en çok kafa karıştıran konulardan biridir. this
‘in değeri, fonksiyonun nasıl çağrıldığına bağlı olarak değişir. Temel olarak, this
, fonksiyonu çağıran nesneye referans verir:
- Global kapsamda:
this
, global nesneye (tarayıcıdawindow
, Node.js’deglobal
) referans verir. - Fonksiyon çağrısında: Eğer fonksiyon “normal” bir şekilde çağrılırsa (örneğin,
fonksiyonAdi()
),this
, global nesneye referans verir (strict moddaundefined
olur). - Metot çağrısında: Eğer fonksiyon bir nesnenin metodu olarak çağrılırsa (örneğin,
nesne.metotAdi()
),this
, o nesneye referans verir. call
,apply
vebind
ile: Bu metotlar,this
‘in değerini manuel olarak belirlememizi sağlar.- Arrow fonksiyonlarında Arrow fonksiyonlar kendi this bağlamını oluşturmazlar this’in değeri, fonksiyonun tanımlandığı yerdeki (lexical scope)
this
değeriyle aynıdır.
Prototip Tabanlı OOP ve ES6 Sınıfları
JavaScript, prototip tabanlı bir nesne yönelimli programlama dilidir. Bu, sınıflar yerine (klasik OOP’deki gibi), nesnelerin prototipler aracılığıyla özellik ve metotları miras aldığı anlamına gelir. Her nesnenin, özelliklerini ve metotlarını miras aldığı bir prototip nesnesi vardır. Bir nesnenin bir özelliğine erişmeye çalıştığımızda, JavaScript önce nesnenin kendisine bakar, eğer özelliği bulamazsa prototip zincirinde yukarı doğru aramaya devam eder.
ES6 (ECMAScript 2015), JavaScript’e sınıf (class
) sözdizimini getirmiştir. Ancak, bu sınıflar aslında prototip tabanlı miras almanın üzerine inşa edilmiş bir “sözdizimsel şekerdir” (syntactic sugar). Yani, arka planda hala prototip tabanlı miras alma mekanizması çalışır. ES6 sınıfları, daha okunaklı ve tanıdık bir OOP yapısı sunar:
class
: Sınıf tanımlamak için kullanılır.class Urun { ... }
constructor
: Sınıfın kurucu metodudur. Nesne oluşturulduğunda otomatik olarak çağrılır.constructor(ad, fiyat) { this.ad = ad; this.fiyat = fiyat; }
extends
: Başka bir sınıftan miras almak için kullanılır.class SepetUrunu extends Urun { ... }
super
: Üst sınıfın kurucusuna veya metotlarına erişmek için kullanılır.super(ad, fiyat);
Örnek Uygulama: Alışveriş Sepeti
Şimdi, öğrendiğimiz kavramları kullanarak basit bir alışveriş sepeti uygulaması geliştirelim:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | class Urun { constructor(ad, fiyat) { this.ad = ad; this.fiyat = fiyat; } bilgileriGoster() { return `${this.ad} - ${this.fiyat} TL`; } } class Sepet { constructor() { this.urunler = []; } urunEkle(urun) { this.urunler.push(urun); } toplamTutar() { return this.urunler.reduce((toplam, urun) => toplam + urun.fiyat, 0); } sepetiGoster() { if (this.urunler.length === 0) { return "Sepetiniz boş."; } const urunListesi = this.urunler.map(urun => urun.bilgileriGoster()).join(' '); return `${urunListesi} Toplam: ${this.toplamTutar()} TL`; } } const urun1 = new Urun("Elma", 5); const urun2 = new Urun("Armut", 7); const sepet = new Sepet(); sepet.urunEkle(urun1); sepet.urunEkle(urun2); console.log(sepet.sepetiGoster()) |
Bu makalede, JavaScript’in fonksiyon türleri (anonim, arrow, geri çağırma, async/await), closure kavramı, this
anahtar kelimesi, prototip tabanlı OOP ve ES6 sınıfları gibi önemli konularını ele aldık. Fonksiyonların farklı türlerini ve kullanım alanlarını, closure’ların değişkenlere erişim ve modülerlik sağlama yeteneğini, this
‘in çağrıldığı yere göre nasıl değiştiğini ve JavaScript’in prototip tabanlı miras alma mekanizmasını inceledik. ES6 sınıflarının, bu mekanizma üzerine inşa edilmiş bir sözdizimsel kolaylık olduğunu gördük. Son olarak, tüm bu bilgileri bir araya getirerek basit bir alışveriş sepeti uygulaması örneği geliştirdik.
Bu temel kavramları anlamak, JavaScript’te daha yetkin olmanızı, daha okunaklı ve verimli kod yazmanızı sağlayacaktır. Öğrendiğiniz bilgileri pratik projelerde uygulayarak pekiştirebilir ve JavaScript yolculuğunuzda kendinizi sürekli geliştirebilirsiniz.