this Çağrı Anında Belirlenir
JavaScript'te this kullanımına dair kafa karışıklığının büyük çoğunluğu tek bir yanlış varsayımdan kaynaklanır: this'in fonksiyonun tanımlandığı yere bağlı olduğunu sanmak. Oysa durum böyle değil. this, fonksiyonun nasıl çağrıldığına göre belirlenir.
Aynı fonksiyonu iki farklı şekilde çağırdığımızda ne olduğuna bakalım:
Aynı fonksiyon, ama this farklı. İlk çağrıda noktadan önce user var, dolayısıyla this user oluyor. İkinci çağrıda noktadan önce hiçbir şey yok, bu yüzden this undefined. Fonksiyonun kendisi değişmedi — değişen tek şey çağrı biçimi.
Şunu aklınızın bir köşesinde tutun: this'in ne olduğunu anlamak için tanıma değil, çağrıya bakın.
Dört Bağlama (Binding) Kuralı
JavaScript'te this değerinin belirlenmesinin dört farklı yolu var. this ile ilgili aklınıza takılacak hemen hemen her sorunun cevabı, bu dört kuraldan hangisinin devreye girdiğini bulmaktan geçiyor.
1. Metot çağrısı: obj.fn()
Bir fonksiyon, bir nesnenin özelliği olarak çağrıldığında this o nesneye işaret eder:
Noktadan önceki şey this olur. Bu kadar basit.
2. Düz çağrı: fn()
Önünde herhangi bir nesne olmadan çağrıldığında, this strict mode'da (modüller ve sınıflar bunu otomatik olarak açar) undefined; sloppy mode'da ise global nesne olur:
İşte tam da bu noktada o meşhur "this is undefined" hatası karşımıza çıkıyor. Bir metodu ait olduğu nesneden söküp aldığınız anda, metot çağrısı sıradan bir fonksiyon çağrısına dönüşüyor:
counter. olmadan çağırdığımızda hiçbir bağlama kalmıyor. Fonksiyon, hangi nesneden geldiğini hatırlamıyor.
3. Açık binding: .call(), .apply(), .bind()
this değerini istediğin şeye zorla sabitleyebilirsin:
.call ve .apply fonksiyonu anında çalıştırır; aralarındaki tek fark, argümanları nasıl aldıklarıdır. .bind ise this değeri kalıcı olarak sabitlenmiş yeni bir fonksiyon döndürür — özellikle callback'lerde işe yarar.
4. new ile çağırma: new Fn()
Bir fonksiyonu new ile çağırdığınızda yepyeni bir nesne oluşturulur ve this bu nesneye bağlanır:
Sınıflar da arka planda bu mekanizmayı kullanır. İlerleyen bölümlerde sınıflara da değineceğiz.
Arrow Function'larda this Davranışı
Arrow function'lar yukarıdaki kuralları bilinçli olarak çiğner. this'i hiç bağlamazlar — onu tanımlandıkları andaki dış kapsamdan (scope) miras alırlar ve orada dondururlar:
Modül seviyesindeki ok fonksiyonu, modülün this değerini yakalar — ki bu da undefined'dır. user.arrow() şeklinde çağrılmış olsa bile, arrow function this'i yeniden bağlamayı reddeder.
Kulağa bug gibi geliyor ama aslında olayın bütün esprisi bu. Arrow function'lar asıl değerini metotların içinde gösterir; yani dıştaki this'i olduğu gibi korumak istediğinde:
setInterval içindeki ok fonksiyonu, this değerini start metodundan miras alır; start de timer.start() şeklinde çağrıldığı için this.seconds sorunsuz çalışır. Orada klasik bir function kullansaydık, o fonksiyonun kendi this'i olurdu (ki bu da setInterval'in ne verdiğine bağlıdır) ve kod çuvallardı.
Pratik kural: metotların içindeki callback'lerde ok fonksiyonu kullanın. Metotların kendisi için normal fonksiyonlarda kalın.
Klasik Callback Tuzağı
this'in en sık tökezlediği yer burasıdır. Bir metodu callback olarak geçirdiğiniz anda bağlamını kaybeder:
setTimeout, fonksiyonu c.increment() şeklinde değil, düz bir çağrıyla tetikliyor. Bunu çözmenin üç yolu var:
Üçü de işini görür. Genelde en anlaşılır olanı arrow function ile sarmalamaktır.
Üst seviyede this
Üst seviyedeki this'in değeri, kodun nerede çalıştığına göre değişir:
- Tarayıcıda script (module değil):
this,window'u gösterir. - ES module (yani modern bundle'lanmış kodların büyük kısmı):
this,undefined'dır. - Node.js CommonJS modülü:
this,module.exports'a karşılık gelir.
Ortamdan bağımsız şekilde global nesneye güvenilir biçimde erişmek istiyorsan globalThis kullan:
Pratikte üst seviyedeki this'e bel bağlamamak en sağlıklısı. Gerçekten global nesneye erişmen gerekiyorsa globalThis kullan; onun dışında değerleri açıkça parametre olarak dolaştırmak çok daha temiz olur.
Hızlı Karar Ağacı
Bir yerde this gördüğünde ne olacağından emin değilsen, şu listeyi sırasıyla uygula:
- Fonksiyon bir arrow function mı? O zaman
this, dış kapsamdakithisne ise odur. Çağrının nereden yapıldığı hiç önemli değil. newile mi çağrıldı? O zamanthis, yeni oluşturulan nesnedir..call,.applyile ya da bind edilmiş bir fonksiyon olarak mı çağrıldı? O zamanthis, oraya verilen değerdir.obj.method()şeklinde mi çağrıldı? O zamanthis,obj'dir.- Düpedüz
fn()olarak mı çağrıldı? Strict mode'dathis,undefinedolur.
Bu sıralama, tam da bu sırayla, her durumu çözer.
Sırada: Higher-Order Functions
Artık this senin için bir muamma olmaktan çıktığına göre, JavaScript'i bu kadar etkili yapan kalıba geçebiliriz: fonksiyonları değer gibi bir yerden bir yere taşımak. Bir sonraki konumuz higher-order functions — yani başka fonksiyonları parametre olarak alan ya da döndüren fonksiyonlar — ve bunların array metotlarına, event handler'lara ve gerçek dünyadaki JavaScript kodunun büyük kısmına nasıl güç verdiği.
Sıkça Sorulan Sorular
JavaScript'te this neyi ifade eder?
this neyi ifade eder?this, fonksiyonun tanımlandığı yeri değil, çağrıldığı nesneyi işaret eder. Örneğin user.greet() çağrısında this değeri user olur. Ama düz bir greet() çağrısında strict mode'da this undefined, sloppy mode'da ise global nesnedir. Yani kural basit: tanım yeri değil, çağrı yeri belirleyici.
Fonksiyonumun içinde this neden undefined oluyor?
this neden undefined oluyor?Büyük ihtimalle bir metodu nesnesinden kopardınız ve tek başına çağırdınız ya da callback olarak ilettiniz. const fn = user.greet; fn(); yazdığınız anda bağlama kaybolur — çünkü çağrı sırasında noktanın solunda bir nesne yok. Çözüm için .bind(user) kullanabilir, arrow function ile sarmalayabilir veya doğrudan user.greet() şeklinde çağırabilirsiniz.
Arrow function'larda this nasıl farklı davranır?
this nasıl farklı davranır?Arrow function'ların kendi this değeri yoktur. Tanımlandıkları andaki dış kapsamın this değerini miras alırlar. Bu yüzden bir metodun içindeki callback'lerde dıştaki this'i korumak istediğinizde biçilmiş kaftandır. Bunun bir sonucu da şu: .call(), .apply() ve .bind() bir arrow function'ın this değerini değiştiremez.
Script'in en üst seviyesinde this nedir?
this nedir?Tarayıcıda normal bir script'te en üst seviyedeki this, window nesnesidir. ES modüllerinde undefined döner. Node.js CommonJS modüllerinde ise module.exports'u işaret eder. Ortamdan bağımsız, her zaman global nesneyi veren referans ise globalThis'tir.