JavaScript'te Closure’lar

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.

  1. Fonksiyon tanımı (bizzat fonksiyonun kendisi)

  2. 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.

YouTube Video