TypeScript'te Closure

TypeScript'te Closure

Bu makalede, TypeScript'teki closure kavramını açıklayacağız.

YouTube Video

TypeScript'te Closure

Closure Nedir?

Closure, bir fonksiyonun tanımlandığı kapsamı (ortamı) referans olarak tutma yeteneğidir; bu fonksiyon kapsam dışında çağrılsa bile bu ortamı korumasına olanak sağlar. Aşağıda, closure kavramı tip açıklamalarıyla birlikte açıklanacaktır.

Basitçe söylemek gerekirse, closure bir fonksiyon ile fonksiyonun tanımlandığı değişken ortamını birleştirir ve fonksiyon çağrıldığında bu ortama erişim sağlar.

Closure Mekanizmasının Temelleri

TypeScript'te, bir fonksiyon başka bir fonksiyon içinde tanımlandığında, içteki fonksiyonun dıştaki fonksiyonun değişkenlerine erişebildiği görülür. Aşağıda tip açıklamalarıyla birlikte temel bir closure örneği verilmiştir.

 1function outerFunction(): () => void {
 2    let outerVariable: string = "I am from outer function";
 3
 4    function innerFunction(): void {
 5        // The inner function accesses the variable of the outer function
 6        console.log(outerVariable);
 7    }
 8
 9    return innerFunction;
10}
11
12const closure: () => void = outerFunction();
13closure();  // "I am from outer function"
  • outerFunction fonksiyonunun dönüş tipi () => void'dir, yani bu fonksiyon başka bir fonksiyon döndürür.
  • innerFunction'ın tipi açıkça void olarak belirlenmiştir; yani herhangi bir dönüş değeri yoktur.

Closure Kullanım Alanları ve Avantajları

Veri Kapsülleme

Aşağıda veri kapsülleme için closure'ın tip açıklamalarıyla birlikte bir örneği verilmiştir.

 1function createCounter(): () => number {
 2    let count: number = 0;
 3
 4    return function (): number {
 5        count += 1;
 6        return count;
 7    };
 8}
 9
10const counter: () => number = createCounter();
11console.log(counter());  // 1
12console.log(counter());  // 2
13console.log(counter());  // 3
  • createCounter fonksiyonu () => number tipinde bir fonksiyon döndürür.
  • count değişkeni number tipiyle tanımlanmıştır ve closure içinde işlenir.

Üst Düzey Fonksiyonlar (Higher-Order Functions)

Closure'lar, üst düzey fonksiyonlar oluştururken oldukça faydalıdır. Aşağıda net tip açıklamalarıyla birlikte bir üst düzey fonksiyon örneği verilmiştir.

 1function createMultiplier(multiplier: number): (value: number) => number {
 2    return function (value: number): number {
 3        return value * multiplier;
 4    };
 5}
 6
 7const double: (value: number) => number = createMultiplier(2);
 8console.log(double(5));  // 10
 9
10const triple: (value: number) => number = createMultiplier(3);
11console.log(triple(5));  // 15
  • createMultiplier, number tipinde bir argüman alır ve (value: number) => number tipinde bir fonksiyon döndürür.
  • İçteki fonksiyon da value parametresini number tipinde alır ve sonucu number tipinde döndürür.

TypeScript'te Closure Kullanımı Örneği

Tip açıklamalarıyla birlikte closure şeklinde aralıklı bir sayaç uygulaması gerçekleştirin.

 1function rangeCounter(min: number, max: number): () => number | string {
 2    let count: number = min;
 3
 4    return function (): number | string {
 5        if (count <= max) {
 6            return count++;
 7        } else {
 8            return `Count has exceeded the maximum value: ${max}`;
 9        }
10    };
11}
12
13const counter: () => number | string = rangeCounter(1, 5);
14
15console.log(counter());  // 1
16console.log(counter());  // 2
17console.log(counter());  // 3
18console.log(counter());  // 4
19console.log(counter());  // 5
20console.log(counter());  // "Count has exceeded the maximum value: 5"
  • rangeCounter fonksiyonu, bir number ya da string döndüren bir fonksiyon döndürür.
  • İçteki fonksiyonda, count değeri max'ı aşarsa bir string tipinde mesaj döner; aksi halde number değer döndürür.

Closure Kullanırken Dikkat Edilmesi Gerekenler

Closure Kaynaklı Olası Bellek Sızıntıları

Closure'lar dış kapsamdan değişkenleri tutabilir ve bu durum bazen bellek sızıntılarına sebep olabilir. Gereksiz closure'ların bellekte kalmasını önlemek için açıkça serbest bırakılması gerekir.

 1function createLeak(): () => void {
 2    // Large array consuming significant memory
 3    const largeArray: string[] = new Array(1000000).fill("leak");
 4
 5    // Closure capturing `largeArray`
 6    return function (): void {
 7        console.log(largeArray[0]); // Using the captured array
 8    };
 9}
10
11// Create a closure that holds a reference to the large array
12let leakyFunction = createLeak();
13
14// The large array is not released as `leakyFunction` still references it
15
16// When the object is no longer needed
17leakyFunction = null; // Explicitly remove the reference
  • Bu kodda, createLeak fonksiyonu içinde oluşturulan largeArray değişkeni kapsam dışına çıktığında serbest bırakılması gerekir, ancak closure largeArray'ı tuttuğu için bu gerçekleşmez. leakyFunction var olduğu sürece, bu gereksiz bellek tutulmaya devam edecektir.
  • Bir nesne veya değişken artık gerekmediğinde, referansını null yaparsanız çöp toplayıcı (garbage collector) bunu algılayıp belleği serbest bırakır.

Döngülerde Closure'ın Yanlış Kullanımı

Bir döngüde closure oluşturulurken, aynı değişkene referans verme konusunda sorunlar yaşanabilir. Aşağıdaki örnek, i değişkeninin düzgün çalışmadığı bir durumu göstermektedir.

1for (var i: number = 0; i < 3; i++) {
2    setTimeout((): void => {
3        console.log(i);
4    }, 1000);
5}
6// Output: 3, 3, 3

Bu kod, istenen sonucu vermez, çünkü döngünün sonunda i değişkeni 3 değerini alır. Bunu düzeltmek için ya let ile ayrı bir kapsam oluşturulmalı ya da hemen çağrılan fonksiyon kullanılmalıdır.

1for (let i: number = 0; i < 3; i++) {
2    setTimeout((): void => {
3        console.log(i);
4    }, 1000);
5}
6// Output: 0, 1, 2

let kullanarak, her döngü yinelemesinde i için ayrı bir kapsam oluşturulur ve beklenen sonuç elde edilir.

Özet

TypeScript'te closure'lar, tip sistemi sayesinde daha güvenli ve öngörülebilir kodlar yazılmasını sağlar. Closure'ların doğru kullanımı veri kapsülleme ve üst düzey fonksiyonların esnek tasarımını mümkün kılar. Ayrıca, closure kullanırken bellek yönetimine ve istenmeyen kapsam referanslarına dikkat edilmelidir.

Yukarıdaki makaleyi, YouTube kanalımızda Visual Studio Code'u kullanarak takip edebilirsiniz. Lütfen YouTube kanalını da kontrol edin.

YouTube Video