Closure sa TypeScript

Closure sa TypeScript

Sa artikulong ito, ipapaliwanag natin ang tungkol sa mga closure sa TypeScript.

YouTube Video

Closure sa TypeScript

Ano ang Closure?

Ang closure ay tumutukoy sa kakayahang mapanatili ang mga sanggunian sa saklaw o kapaligiran kung saan tinukoy ang isang function, kahit tawagin ang function sa labas ng nasabing saklaw. Sa ibaba, ipapaliwanag ang mga closure kasama ang mga type annotations.

Sa madaling salita, ang closure ay pinagsasama ang isang function at ang kapaligiran ng variable kung saan ito itinukoy, kaya nagbibigay-daan upang ma-access ang kapaligiran kapag tinawag ang function.

Batayang Mekanismo ng Mga Closure

Sa TypeScript, kapag ang isang function ay tinukoy sa loob ng ibang function, napapatunayan na maaaring ma-access ng panloob na function ang mga variable ng panlabas na function. Narito ang isang pangunahing halimbawa ng closure na may mga type annotations.

 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"
  • Ang return type ng outerFunction ay () => void, na nagpapahiwatig na nagsasauli ito ng isang function.
  • Ang uri ng innerFunction ay hayagang itinakda sa void, na nagpapakita na wala itong isasauling halaga.

Mga Gamit at Bentahe ng Mga Closure

Encapsulation ng Data

Sa ibaba ay isang halimbawa ng closure na may type annotations para sa encapsulation ng 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
  • Ang function na createCounter ay nagsasauli ng isang function na may uri na () => number.
  • Ang variable na count ay tinukoy bilang number na uri at binabago sa loob ng closure.

Mas Mataas na Antas ng Mga Function

Ang mga closure ay kapaki-pakinabang kapag gumagawa ng mas mataas na antas ng mga function. Sa ibaba ay isang halimbawa ng mas mataas na antas ng function na may malinaw na type annotations.

 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
  • Ang createMultiplier ay tumatanggap ng argumento na may uri na number at nagsasauli ng isang function na may uri na (value: number) => number.
  • Ang panloob na function ay tumatanggap din ng value bilang uri na number at isasauli ang resulta bilang uri na number.

Halimbawa ng Pagpapatupad ng Mga Closure sa TypeScript

Ipatupad ang isang range-bound na counter bilang isang closure na may karagdagang mga type annotations.

 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"
  • Ang function na rangeCounter ay nagsasauli ng isang function na nagsasauli ng alinman sa number o string.
  • Sa panloob na function, kung ang count ay lumampas sa max, nagbibigay ito ng mensaheng uri ng string; kung hindi, nagbibigay ito ng uri ng number.

Mga Pag-iingat Kapag Gumagamit ng Closures

Posibleng Memory Leaks mula sa Closures

Maaaring panatilihin ng closures ang mga variable mula sa panlabas na saklaw, na maaaring magdulot paminsan-minsan ng memory leaks. Ang mga hindi kailangang closures ay kailangang tahasang alisin mula sa memorya.

 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
  • Sa code na ito, ang largeArray na nilikha sa loob ng createLeak ay inaasahang maaalis kapag ito ay lumabas ng saklaw, ngunit hindi ito nangyayari dahil kinukuha ng closure ang largeArray. Hangga't umiiral ang leakyFunction, ang hindi kailangang memoryang ito ay magpapatuloy na mapanatili.
  • Kapag ang isang object o variable ay hindi na kailangan, ang pag-set sa reference nito sa null ay magpapahintulot sa garbage collector na makita ito at palayain ang memorya.

Maling Paggamit ng Closures sa Mga Loops

Kapag lumilikha ng closures sa loob ng isang loop, maaaring magkaroon ng mga isyu sa pag-refer sa parehong variable. Ang sumusunod na halimbawa ay nagpapakita ng isang kaso kung saan ang variable na i ay hindi gumagana nang maayos.

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

Hindi nagbibigay ang code na ito ng nais na resulta dahil ang i ay tumutukoy sa halagang 3 sa dulo ng loop. Upang ayusin ito, gamitin ang let upang paghiwalayin ang saklaw o gumamit ng isang agad na tinawag na function.

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

Sa pamamagitan ng paggamit ng let, ang saklaw ng i ay hiwalay para sa bawat pag-ulit ng loop, nagbibigay ng inaasahang mga resulta.

Buod

Sa TypeScript, ang closures ay maaaring humantong sa mas ligtas at mas mahuhulaang code sa pamamagitan ng paggamit sa type system. Ang tamang paggamit ng closures ay nagpapahintulot sa pag-encapsulate ng data at nababaluktot na disenyo ng mas mataas na antas ng mga function. Dagdag pa rito, kailangang mag-ingat sa pamamahala ng memorya at mga hindi sinasadyang pag-refer sa saklaw kapag gumagamit ng closures.

Maaari mong sundan ang artikulo sa itaas gamit ang Visual Studio Code sa aming YouTube channel. Paki-check din ang aming YouTube channel.

YouTube Video