Für Personen, die ihr Abenteuer mit JavaScript beginnen, sind Closures eines der schwierigsten Themen. In diesem Artikel werde ich versuchen, dieses interessante Thema zu präsentieren, indem ich die Fragen zu den Closures beantworte und Beispiele für ihre Verwendung im Code präsentiere.

In JavaScript gibt es viele Definitionen von Closures. Hauptsächlich geht es darum, dass es sich um einen separaten Bereich handelt, der von der Hauptfunktion erstellt wird, in dem alle Variablen und internen Funktionen vom restlichen Code unabhängig sind. Der Vorteil von Closures besteht darin, dass interne Funktionen Zugriff auf externe Funktionen haben, während externe Funktionen keinen Zugriff auf die internen Funktionen haben.

Das Thema ist von der Definition her recht einfach, aber immer noch nicht vollständig verstanden.

Dies wird am besten durch ein einfaches Beispiel veranschaulicht:

var myName = ‘Marcin’;
var myAge = 31;
function changeData(){
    var myName = ‘Piotrek’;
    myAge = 32;
} 
changeData();
console.log(myName);
console.log(myAge);

In diesem Fall werden Marcin und 32 auf die Konsole gedruckt. Die Variable myName in der Funktion changeData ist eine Variable, auf die nur die Funktion myName Zugriff hat.

Lassen Sie uns ein anderes Beispiel analysieren:

function buildName(name){
    var greeting = “Hello, ” + name;
    return greeting;
} 

Die Funktion buildName() deklariert die lokale Variable greeting und gibt diese zurück. Bei jedem Funktionsaufruf wird ein neuer Bereich mit einer neuen lokalen Variablen erstellt. Nach dem Ausführen dieser Funktion können wir uns auf diesen Bereich nicht mehr beziehen.

Die Closures kommen uns zu Hilfe:

function myName(name){ 
    var greeting = "Cześć, " + name; 
    var sayName = function(){
        var welcome = greeting + " Pozdrawiam!";
        console.log(welcome);
    }; return sayName;
} 
var sayMyName = myName("Marcin");
sayMyName();  // Cześć, Marcin Pozdrawiam!
sayMyName();  // Cześć, Marcin Pozdrawiam!
sayMyName();  // Cześć, Marcin Pozdrawiam!

Die Funktion sayName() aus diesem Beispiel ist eine Closure.

Die Funktion sayName() hat eine eigene lokale Reichweite (mit der Variable welcome) und hat auch Zugriff auf die Reichweite der externen Funktion. In diesem Fall ist es die Variable greeting aus der Funktion myName().

Normalerweise wird der Bereich nach der Ausführung der Funktion zerstört und es besteht kein Zugriff darauf. Nach dem Ausführen der Funktion myName() wird der Bereich in diesem Fall nicht gelöscht. Die Funktion sayMyName() hat immer noch Zugriff darauf.

Die Closure dient als ein Tor zwischen dem globalen Kontext und dem externen Bereich.

Zum Schluss möchte ich ein Beispiel vorstellen, das bei Vorstellungsgesprächen häufig besprochen wird, nämlich der berühmte setTimeout loop.

for(var i = 0; i < 5; i++){
    setTimeout(function(){
        console.log(i);
    }, 300);
} 

Was bewirkt dieser Code? Der erste Gedanke ist, Zahlen von 0 bis 4 auf der Konsole zu drucken. Dies ist ein häufiger Fehler. Dieser Code wird fünfmal die Fünf drucken.

Warum passiert das? Die Variable i ist in diesem Fall eine globale Variable und jedes Mal übergeben wir den gleichen Wert der Variable i.

Wie bekommt man das Ergebnis von 0 bis 4?

Wir können Closures verwenden, und zwar die Funktion IIFE (Immediately-Invoked Function Expression). Dieses Beispiel sieht so aus:

for (var i = 0; i < 5; i++){
    (function (e){
        setTimeout(function (){
            console.log(e);
        }, 300);
    })(i);
} 

Warum erreichen wir jetzt die beabsichtigte Wirkung? Weil die anonyme Funktion ihren eigenen Bereich hat und jedes Mal übergeben wir ihr einen anderen Wert der Variable i.

Beim ersten Loop rufen wir sofort den IIFE mit dem Parameter i mit dem aktuellen Wert 0 (Wert von der Closure) auf. Der Aufruf von IIFE bewirkt die Einstellung der Anweisung console.log mit der Verzögerung von 300 ms, wobei der Wert der Variable e gleich 0 ist. Ein neuer Übergang durch den Loop beginnt. Diesmal hat die Variable i den Wert 1 und wird an IIFE übergeben, die die Ausführung von console.log in 300 ms mit der Variable e mit dem Wert 1 und so bis 4 festlegt.

Zusammengefasst:

Wir können Closures in Situationen einsetzen, in denen:

  • wir die Einkapselung von Methoden emulieren wollen
  • wir normalerweise ein Objekt nur mit einer Methode verwenden würden