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"
- Der Rückgabetyp von
outerFunction
ist() => void
, was bedeutet, dass sie eine Funktion zurückgibt. - Der Typ von
innerFunction
ist explizit aufvoid
gesetzt, was darauf hinweist, dass sie keinen Rückgabewert hat.
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 vom Typ() => number
zurück. - 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. 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
nimmt ein Argument vom Typnumber
entgegen und gibt eine Funktion vom Typ(value: number) => number
zurück.- Die interne Funktion nimmt ebenfalls
value
als Typnumber
entgegen und gibt das Ergebnis als Typnumber
zurück.
Beispiel für die Implementierung von Closures in TypeScript
Implementieren Sie einen Bereichszähler als Closure mit erweiterten Typannotationen.
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 die Variable i
nicht korrekt funktioniert.
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.