Closure dalam TypeScript

Closure dalam TypeScript

Dalam artikel ini, kami akan menerangkan tentang closure dalam TypeScript.

YouTube Video

Closure dalam TypeScript

Apakah itu Closure?

Closure merujuk kepada keupayaan untuk mengekalkan rujukan kepada skop (persekitaran) di mana fungsi itu telah ditakrifkan, walaupun fungsi itu dipanggil di luar skop tersebut. Di bawah, closure akan diterangkan termasuk penjelasan jenis (type annotation).

Secara ringkas, closure menggabungkan satu fungsi dan persekitaran pembolehubah di mana fungsi itu ditakrifkan, membolehkan akses kepada persekitaran itu apabila fungsi dipanggil.

Mekanisme Asas Closure

Dalam TypeScript, apabila satu fungsi ditakrifkan di dalam fungsi lain, adalah jelas bahawa fungsi dalaman boleh mengakses pembolehubah fungsi luaran. Berikut adalah contoh asas closure dengan penanda jenis.

 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 memulangkan fungsi dalaman innerFunction.
  • innerFunction memaparkan nilai pembolehubah outerVariable fungsi luaran.

Kegunaan dan Kelebihan Closure

Closure Data (Penyembunyian Data)

Di bawah adalah contoh closure dengan penanda jenis untuk tujuan penyembunyian (enkapsulasi) data.

 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 memulangkan fungsi yang memulangkan nilai jenis number.
  • Pembolehubah count ditakrifkan dengan jenis number dan dimanipulasi dalam closure.

Fungsi Tertib Tinggi

Closure sangat berguna ketika mencipta fungsi tertib tinggi. Di sini, fungsi aras tinggi ialah fungsi yang mengambil fungsi lain sebagai argumen atau mengembalikan fungsi sebagai hasilnya. Berikut adalah contoh fungsi tertib tinggi disertai penanda jenis yang jelas.

 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 ialah fungsi aras tinggi yang mencipta fungsi untuk mendarab dengan nombor yang diterima sebagai argumen.
  • Fungsi pendaraban dalaman juga mengambil nombor dan mengembalikan hasil pendaraban sebagai nombor.

Contoh Pelaksanaan Closure dalam TypeScript

Mari kita lihat juga contoh melaksanakan penjejak kiraan berdasarkan julat sebagai penutupan.

 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"
  • Fungsi rangeCounter memulangkan satu fungsi yang akan memulangkan sama ada number atau string.
  • Dalam fungsi dalaman, jika count melebihi max, ia akan memulangkan mesej jenis string; jika tidak, ia memulangkan jenis number.

Langkah Berjaga-jaga Ketika Menggunakan Closure

Potensi Kebocoran Memori daripada Closure

Closure boleh mengekalkan pembolehubah dari skop luar, yang kadang-kadang boleh menyebabkan kebocoran memori. Closure yang tidak diperlukan perlu dilepaskan dari memori secara eksplisit.

 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
  • Dalam kod ini, largeArray yang dicipta di dalam createLeak sepatutnya dilepaskan apabila ia keluar dari skop, tetapi tidak kerana closure telah menangkap (capture) largeArray. Selagi leakyFunction wujud, memori yang tidak diperlukan ini akan terus dikekalkan.
  • Apabila objek atau pembolehubah tidak diperlukan lagi, menetapkan rujukannya kepada null membolehkan pengumpul sampah (garbage collector) mengesannya dan melepaskan memori.

Penyalahgunaan Closure dalam Gelung (Loop)

Apabila mencipta closure di dalam satu gelung, mungkin timbul masalah merujuk kepada pembolehubah yang sama. Contoh berikut menunjukkan kes di mana pembolehubah i yang diisytiharkan dengan var tidak berfungsi dengan betul.

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

Kod ini tidak memberikan hasil yang diinginkan kerana i merujuk kepada nilai 3 di penghujung gelung. Untuk membetulkan situasi ini, gunakan let untuk memisahkan skop atau gunakan fungsi yang dipanggil serta-merta (immediately-invoked function).

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

Dengan menggunakan let, skop untuk i dipisahkan untuk setiap iterasi gelung, lalu memberikan hasil yang dijangkakan.

Ringkasan

Dalam TypeScript, closure boleh menghasilkan kod yang lebih selamat dan boleh dijangka dengan memanfaatkan sistem jenis. Penggunaan closure yang betul membolehkan enkapsulasi data dan reka bentuk fungsi tertib tinggi yang fleksibel. Selain itu, perhatian harus diberikan dalam pengurusan memori dan rujukan skop yang tidak sengaja ketika menggunakan closure.

Anda boleh mengikuti artikel di atas menggunakan Visual Studio Code di saluran YouTube kami. Sila lihat juga saluran YouTube kami.

YouTube Video