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"
  • Jenis pulangan bagi outerFunction ialah () => void, menunjukkan bahawa ia memulangkan satu fungsi.
  • Jenis bagi innerFunction dinyatakan secara eksplisit sebagai void, menunjukkan ia tidak mempunyai nilai pulangan.

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
  • Fungsi createCounter memulangkan satu fungsi dengan jenis () => number.
  • Pembolehubah count ditakrifkan dengan jenis number dan dimanipulasi dalam closure.

Fungsi Tertib Tinggi

Closure sangat berguna ketika mencipta fungsi tertib tinggi. 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 menerima argumen jenis number dan memulangkan satu fungsi dengan jenis (value: number) => number.
  • Fungsi dalaman juga menerima value sebagai jenis number dan memulangkan hasil sebagai jenis number.

Contoh Pelaksanaan Closure dalam TypeScript

Laksanakan kaunter dengan had julat sebagai closure dengan penanda jenis ditambah.

 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 situasi di mana pembolehubah i 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