JavaScript'te Closure’lar
Bu makalede JavaScript’teki closure’lar açıklanmaktadır.
YouTube Video
JavaScript'te Closure’lar
JavaScript'te 'closure' çok önemli ve güçlü kavramlardan biridir. Closure’ları anlayarak fonksiyonların davranışı ve kapsamı, JavaScript’in asenkron işlemleri ve olay yönetimi gibi pek çok durumda faydalı bilgiler edinebilirsiniz. Burada, closure’ların temel tanımından somut örneklerine ve uygulamalarına kadar her şeyi detaylı olarak açıklayacağız.
Closure nedir?
Closure, bir fonksiyonun oluşturulduğu kapsamda bulunan değişkenlere, o kapsamın dışında çağrılsa bile erişebilmesini sağlayan mekaniğe verilen isimdir. Closure’lar sayesinde, fonksiyonlar dışardaki değişkenleri sürekli olarak 'hatırlayabilir'.
Closure’lar aşağıdaki iki unsurdan oluşur.
-
Fonksiyon tanımı (bizzat fonksiyonun kendisi)
-
Fonksiyonun tanımlandığı kapsam (fonksiyonun dışında yer alan değişkenler ve diğer fonksiyonlar)
JavaScript’te closure’lar mümkündür çünkü fonksiyonlar, oluşturuldukları kapsamda bulunan değişkenlere erişebilirler.
Temel Örnek
Önce closure’ın temel bir örneğine bakalım. Aşağıdaki kodda, outerFunction
fonksiyonu innerFunction
adında bir fonksiyon döndürür. Buradaki önemli nokta, innerFunction
fonksiyonunun, outerFunction
kapsamı içinde tanımlanmış count
değişkenine erişebilmesidir.
1function outerFunction() {
2 let count = 0;
3
4 function innerFunction() {
5 count++;
6 console.log(`Current count: ${count}`);
7 }
8
9 return innerFunction;
10}
11
12const counter = outerFunction();
13counter(); // Current count: 1
14counter(); // Current count: 2
15counter(); // Current count: 3
Closure’lar Nasıl Çalışır
Yukarıdaki örnekte görüldüğü gibi, outerFunction
çalıştırıldıktan sonra bile, count
değişkeni innerFunction
tarafından saklanmaya devam eder. innerFunction
, hala outerFunction
kapsamına erişebilir ve böylece count
değişkeni innerFunction
içinde güncellenir. Closure’ın temel mantığı budur.
counter
değişkenine atanan aslında innerFunction
fonksiyonudur; böylece, outerFunction
çalışmasını tamamlamış olsa bile count
’un değeri korunur. Bunun nedeni, JavaScript’in fonksiyon tanımlandığı zamandaki kapsamı 'hatırlamaya' devam etmesidir.
Uygulama: Closure’ların Özel (Private) Değişkenler Olarak Kullanımı
Closure’lar, nesne yönelimli programlamada kullanılan 'özel değişkenler' gibi kullanılabilir. Normalde JavaScript’te, nesne özellikleri dışarıdan doğrudan erişilebilirdir; ancak closure kullanılarak, fonksiyon kapsamındaki değişkenlerin dışarıdan doğrudan değiştirilmesi engellenebilir.
Bir sonraki örnekte, createCounter
fonksiyonu bir closure kullanarak sayıcı oluşturur ve özel bir count
değişkenine sahip sayaç döndürür.
1function createCounter() {
2 let count = 0;
3
4 return {
5 increment: function() {
6 count++;
7 console.log(`Count: ${count}`);
8 },
9 decrement: function() {
10 count--;
11 console.log(`Count: ${count}`);
12 },
13 getCount: function() {
14 return count;
15 }
16 };
17}
18
19const myCounter = createCounter();
20myCounter.increment(); // Count: 1
21myCounter.increment(); // Count: 2
22myCounter.decrement(); // Count: 1
23console.log(myCounter.getCount()); // 1
Bu örnekte, count
değişkeni createCounter
fonksiyonu kapsamında tanımlandığı için doğrudan dışarıdan erişilemez. Ancak, increment
ve decrement
metotları üzerinden kontrol edilebilir. Bu şekilde closure kullanarak JavaScript içinde özel değişken kavramını uygulayabilirsiniz.
Closure’ların Pratik Kullanım Örnekleri
Callback Fonksiyonlarla Birlikte Kullanımı
Closure’lar, asenkron işlemleri yönetmek için genellikle callback fonksiyonlarla birlikte kullanılır. Örneğin, bir zamanlayıcı (timer) ile ilgili bir örnek düşünelim.
1function startTimer(duration) {
2 let timeLeft = duration;
3
4 function countdown() {
5 console.log(`Time left: ${timeLeft} seconds`);
6 timeLeft--;
7
8 if (timeLeft >= 0) {
9 setTimeout(countdown, 1000);
10 }
11 }
12
13 countdown();
14}
15
16startTimer(5);
17// Time left: 5 seconds
18// Time left: 4 seconds
19// Time left: 3 seconds
20// Time left: 2 seconds
21// Time left: 1 second
22// Time left: 0 seconds
Bu örnekte, countdown
fonksiyonu, startTimer
kapsamındaki timeLeft
değişkenine erişebilir. Bu şekilde closure’lar, zamanlayıcılar gibi asenkron işlemlerde değişkenlerin durumunu korumak için oldukça yararlıdır.
Olay Yakalayıcılar (Event Handler)
Olay yakalayıcıları ayarlarken de closure’lar oldukça kullanışlıdır. Aşağıdaki örnekte, bir butona kaç kere tıklandığını kaydetmek için closure kullanılır.
1function setupClickCounter(buttonId) {
2 let clickCount = 0;
3
4 const button = document.getElementById(buttonId);
5 button.addEventListener('click', function() {
6 clickCount++;
7 console.log(`Button clicked ${clickCount} times`);
8 });
9}
10
11setupClickCounter('myButton');
Bu durumda, clickCount
her tıklamada artar ve değeri saklanır. Closure kullanarak her butona bağımsız bir sayaç atayabilirsiniz.
Sonuç
Closure’lar, JavaScript’in esnekliğini ve gücünü simgeleyen kavramlardır. Fonksiyon kapsamı içerisinde saklanan değişkenleri tutarak, dışarıdan erişilebilen fonksiyonlar aracılığıyla bu değişkenler üzerinde işlem yapmaya imkan tanır. Bu yapıyı anlayıp kullanarak JavaScript’te daha gelişmiş teknikler edinebilirsiniz.
Closure’lar, olay yönetiminden asenkron işlemlere ve nesne yönelimli programlamanın sözde (pseudo) uygulamalarına kadar çeşitli durumlarda kullanılabilir.
Yukarıdaki makaleyi, YouTube kanalımızda Visual Studio Code'u kullanarak takip edebilirsiniz. Lütfen YouTube kanalını da kontrol edin.