Closure in TypeScript
In diesem Artikel erklären wir Closures in TypeScript.
YouTube Video
Closure in TypeScript
Was ist eine Closure?
Closure bezeichnet die Fähigkeit, Referenzen auf den Gültigkeitsbereich (Umgebung) zu behalten, in dem eine Funktion definiert wurde, selbst wenn die Funktion außerhalb dieses Bereichs aufgerufen wird. Im Folgenden werden Closures einschließlich Typannotationen erklärt.
Einfach ausgedrückt kombiniert eine Closure eine Funktion mit der Variablenumgebung, in der die Funktion definiert wurde, und ermöglicht den Zugang zu dieser Umgebung, wenn die Funktion aufgerufen wird.
Grundmechanismus von Closures
In TypeScript wird deutlich, dass eine innerhalb einer anderen Funktion definierte Funktion auf Variablen der äußeren Funktion zugreifen kann. Hier ist ein einfaches Beispiel für eine Closure mit Typannotationen.
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
gibt die innere FunktioninnerFunction
zurück.innerFunction
zeigt den Wert der VariablenouterVariable
der äußeren Funktion an.
Anwendungsfälle und Vorteile von Closures
Datenkapselung
Nachfolgend ein Beispiel für eine Closure mit Typannotationen zur Datenkapselung.
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
- Die Funktion
createCounter
gibt eine Funktion zurück, die einen Wert vom Typnumber
zurückgibt. - Die Variable
count
ist als Typnumber
definiert und wird innerhalb der Closure verarbeitet.
Höherwertige Funktionen
Closures sind nützlich beim Erstellen von höherwertigen Funktionen. Hier ist eine höhere Funktion eine Funktion, die eine andere Funktion als Argument nimmt oder eine Funktion als Ergebnis zurückgibt. Nachfolgend ein Beispiel für eine höherwertige Funktion mit klaren Typannotationen.
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
ist eine höhere Funktion, die eine Funktion erzeugt, um mit der Zahl zu multiplizieren, die sie als Argument erhält.- Die innere Multiplikationsfunktion nimmt ebenfalls eine Zahl als Argument und gibt das Ergebnis der Multiplikation als Zahl zurück.
Beispiel für die Implementierung von Closures in TypeScript
Schauen wir uns auch ein Beispiel für die Implementierung eines bereichsbasierten Zählers als Closure an.
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"
- Die Funktion
rangeCounter
gibt eine Funktion zurück, die entweder einenumber
oder einenstring
zurückgibt. - In der internen Funktion wird, wenn
count
den Wert vonmax
überschreitet, eine Nachricht vom Typstring
zurückgegeben, andernfalls ein Wert vom Typnumber
.
Vorsichtsmaßnahmen beim Einsatz von Closures
Potentielle Speicherlecks durch Closures
Closures können Variablen aus einem äußeren Gültigkeitsbereich behalten, was gelegentlich zu Speicherlecks führen kann. Nicht benötigte Closures sollten explizit aus dem Speicher entfernt werden.
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
- In diesem Code sollte das in
createLeak
angelegtelargeArray
freigegeben werden, wenn es außerhalb des Gültigkeitsbereichs liegt, aber das geschieht nicht, da die ClosurelargeArray
einfängt. SolangeleakyFunction
existiert, wird dieser unnötige Speicher weiterhin belegt bleiben. - Wenn ein Objekt oder eine Variable nicht mehr benötigt wird, ermöglicht das Setzen des Verweises auf
null
dem Garbage Collector, sie zu erkennen und den Speicher freizugeben.
Missbrauch von Closures in Schleifen
Beim Erstellen von Closures innerhalb einer Schleife kann es zu Problemen kommen, da auf dieselbe Variable verwiesen wird. Das folgende Beispiel zeigt einen Fall, in dem sich die mit var
deklarierte Variable i
nicht korrekt verhält.
1for (var i: number = 0; i < 3; i++) {
2 setTimeout((): void => {
3 console.log(i);
4 }, 1000);
5}
6// Output: 3, 3, 3
Dieser Code liefert nicht das gewünschte Ergebnis, da i
am Ende der Schleife auf den Wert 3 verweist. Um dies zu beheben, verwenden Sie entweder let
, um den Gültigkeitsbereich zu trennen, oder nutzen Sie eine sofort ausgeführte Funktion.
1for (let i: number = 0; i < 3; i++) {
2 setTimeout((): void => {
3 console.log(i);
4 }, 1000);
5}
6// Output: 0, 1, 2
Durch die Verwendung von let
wird für jede Iteration der Schleife ein eigener Gültigkeitsbereich für i
erzeugt, was die erwarteten Ergebnisse liefert.
Zusammenfassung
In TypeScript können Closures dank des Typsystems zu sichererem und vorhersehbarerem Code führen. Der richtige Einsatz von Closures ermöglicht Datenkapselung und eine flexible Gestaltung von höherwertigen Funktionen. Zudem ist beim Einsatz von Closures auf die Speicherverwaltung und unbeabsichtigte Bereichsreferenzen zu achten.
Sie können den obigen Artikel mit Visual Studio Code auf unserem YouTube-Kanal verfolgen. Bitte schauen Sie sich auch den YouTube-Kanal an.