Closure i TypeScript

Closure i TypeScript

I den här artikeln förklarar vi closures i TypeScript.

YouTube Video

Closure i TypeScript

Vad är en Closure?

Closure syftar på möjligheten att behålla referenser till den scope (miljö) där en funktion definierades, även om funktionen anropas utanför den scopen. Nedan förklaras closures, inklusive typanoteringar.

Enkelt uttryckt kombinerar en closure en funktion och den miljö av variabler där funktionen definierades, vilket möjliggör åtkomst till denna miljö när funktionen anropas.

Grundläggande mekanism för closures

I TypeScript, när en funktion definieras inom en annan funktion, blir det tydligt att den inre funktionen kan komma åt variabler från den yttre funktionen. Här är ett grundläggande exempel på en closure med typanoteringar.

 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 för outerFunction är () => void, vilket visar att den returnerar en funktion.
  • Typen för innerFunction är uttryckligen satt till void, vilket betyder att den inte returnerar något värde.

Användning och fördelar med closures

Datainkapsling

Nedan finns ett exempel på en closure med typanoteringar för att kapsla in 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
  • Funktionen createCounter returnerar en funktion av typen () => number.
  • Variabeln count är definierad som number och hanteras inom closuren.

Högre ordningens funktioner

Closures är användbara när man skapar högre ordningens funktioner. Nedan är ett exempel på en högre ordningens funktion med tydliga typanoteringar.

 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 ett argument av typen number och returnerar en funktion av typen (value: number) => number.
  • Den interna funktionen tar också emot value som number och returnerar resultatet som number.

Exempel på implementering av closures i TypeScript

Implementera en intervalbegränsad räknare som en closure med tillagda typanoteringar.

 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"
  • Funktionen rangeCounter returnerar en funktion som returnerar antingen number eller string.
  • I den interna funktionen, om count överstiger max, returneras ett meddelande av string-typ, annars returneras ett number-värde.

Försiktighetsåtgärder vid användning av closures

Möjliga minnesläckor från closures

Closures kan behålla variabler från ett yttre scope, vilket ibland kan orsaka minnesläckor. Onödiga closures måste explicit rensas från 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 denna kod ska largeArray som skapats i createLeak frisläppas när den går utanför scope, men det sker inte eftersom closuren fångar largeArray. Så länge leakyFunction finns kvar kommer detta onödiga minne att hållas kvar.
  • När ett objekt eller en variabel inte längre behövs, kan dess referens sättas till null så att garbage collectorn kan frigöra minnet.

Felaktig användning av closures i loopar

Vid skapande av closures inuti en loop kan det uppstå problem med att hänvisa till samma variabel. Följande exempel visar ett fall där variabeln i inte fungerar korrekt.

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

Den här koden ger inte önskat resultat eftersom i refererar till värdet 3 vid slutet av loopen. För att åtgärda detta, använd antingen let för att separera scope eller använd en omedelbart anropad funktion.

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

Genom att använda let separeras scopen för i för varje iteration och ger de förväntade resultaten.

Sammanfattning

I TypeScript kan closures leda till säkrare och mer förutsägbar kod genom att dra nytta av typsystemet. Korrekt användning av closures möjliggör datainkapsling och flexibel design av högre ordningens funktioner. Dessutom måste man vara noggran med minneshantering och oavsiktliga scope-referenser när man använder closures.

Du kan följa med i artikeln ovan med hjälp av Visual Studio Code på vår YouTube-kanal. Vänligen kolla även in YouTube-kanalen.

YouTube Video