Closure i TypeScript

Closure i TypeScript

I denne artikkelen vil vi forklare closures i TypeScript.

YouTube Video

Closure i TypeScript

Hva er en closure?

Closure refererer til evnen til å beholde referanser til miljøet (scope) der en funksjon ble definert, selv om funksjonen blir kalt utenfor dette miljøet. Nedenfor vil closures bli forklart inkludert typeannotasjoner.

Enkelt sagt kombinerer en closure en funksjon og variabelmiljøet hvor funksjonen ble definert, slik at man får tilgang til det miljøet når funksjonen kalles.

Grunnleggende mekanisme for closures

I TypeScript, når en funksjon er definert inne i en annen funksjon, blir det tydelig at den indre funksjonen har tilgang til variablene til den ytre funksjonen. Her er et grunnleggende eksempel på en closure med typeannotasjoner.

 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"
  • Returtypen til outerFunction er () => void, noe som indikerer at den returnerer en funksjon.
  • Typen til innerFunction er eksplisitt satt til void, som betyr at den ikke har noen returverdi.

Bruk og fordeler med closures

Dataenkapsulering

Nedenfor er et eksempel på en closure med typeannotasjoner for innkapsling av 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-funksjonen returnerer en funksjon av typen () => number.
  • Variabelen count er definert som typen number og blir manipulert innenfor closuren.

Høyereordens funksjoner

Closures er nyttige når man lager høyereordens funksjoner. Nedenfor er et eksempel på en høyereordens funksjon med tydelige typeannotasjoner.

 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 tar et argument av typen number og returnerer en funksjon av typen (value: number) => number.
  • Den interne funksjonen tar også value som en number-type og returnerer resultatet som en number-type.

Eksempel på implementering av closures i TypeScript

Implementer en grensebasert teller som en closure med ekstra typeannotasjoner.

 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-funksjonen returnerer en funksjon som returnerer enten et number eller en string.
  • I den interne funksjonen, hvis count overskrider max, returnerer den en melding av typen string; ellers returnerer den en number-type.

Forholdsregler ved bruk av closures

Potensielle minnelekkasjer fra closures

Closures kan beholde variabler fra et eksternt scope, noe som noen ganger kan føre til minnelekkasje. Unødvendige closures må eksplisitt frigjøres fra minnet.

 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
  • I denne koden skal largeArray som lages inne i createLeak egentlig frigjøres når den går ut av scope, men det skjer ikke fordi closuren fanger largeArray. Så lenge leakyFunction eksisterer, vil dette unødvendige minnet fortsatt bli beholdt.
  • Når et objekt eller en variabel ikke lenger trengs, kan referansen settes til null, slik at søppeloppsamleren kan oppdage den og frigjøre minnet.

Feilbruk av closures i løkker

Når du lager closures inne i en løkke, kan det oppstå problemer med referanse til samme variabel. Følgende eksempel viser en situasjon der variabelen i ikke fungerer slik den skal.

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

Denne koden gir ikke ønsket resultat fordi i refererer til verdien 3 på slutten av løkken. For å fikse dette, bruk enten let for å skille scopes eller bruk en umiddelbart påkalt funksjon.

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

Ved å bruke let blir scopet til i separert for hver løkkeiterasjon, noe som gir forventede resultater.

Sammendrag

I TypeScript kan closures føre til sikrere og mer forutsigbar kode ved å bruke typesystemet. Korrekt bruk av closures muliggjør dataenkapsulering og fleksibel design av høyereordens funksjoner. I tillegg må man være oppmerksom på minnehåndtering og utilsiktede scope-referanser ved bruk av closures.

Du kan følge med på artikkelen ovenfor ved å bruke Visual Studio Code på vår YouTube-kanal. Vennligst sjekk ut YouTube-kanalen.

YouTube Video