EMZETT.
Login

Closure

Kurz: Eine Closure (Funktionsabschluss) ist eine Funktion, die sich die Variablen ihrer Umgebung „merkt“ – auch dann noch, wenn die äußere Funktion längst beendet ist.

Genauer: Closures entstehen, wenn eine innere Funktion auf Variablen der äußeren zugreift und zurückgegeben oder weitergereicht wird. Sie sind die Grundlage für Zähler, Fabriken, Callbacks, Teilanwendung (Currying) und das Modul-Muster in JavaScript. Unterstützt werden sie von JavaScript, Python, Java (Lambda-Ausdrücke), C#, Go, Kotlin, Swift, Rust, Haskell und vielen weiteren.

Im Detail

def zaehler():
    stand = 0
    def erhoehe():
        nonlocal stand
        stand += 1
        return stand
    return erhoehe
 
a = zaehler()
b = zaehler()
print(a(), a(), a())   # 1 2 3
print(b())             # 1  (eigener, getrennter Zustand)
function multiplikator(faktor) {
  return (x) => x * faktor;        // merkt sich "faktor"
}
const verdopple = multiplikator(2);
const verdreifache = multiplikator(3);
console.log(verdopple(10), verdreifache(10)); // 20 30

Wofür?

  • Zustand kapseln: Die Variable stand ist von außen nicht erreichbar, nur über die zurückgegebene Funktion – ähnlich wie ein privates Feld in der Kapselung.
  • Funktionen konfigurieren: multiplikator(2) erzeugt eine spezialisierte Funktion.
  • Ereignisbehandlung: Ein Event-Handler greift auf Daten aus dem Kontext zu, in dem er erstellt wurde.

Stolperfalle: Schleifenvariable

In JavaScript fangen Closures über var dieselbe Variable ein: Alle Handler sehen am Ende denselben Wert. let erzeugt pro Durchlauf eine neue Variable und löst das Problem.

const mitVar = [], mitLet = [];
for (var i = 0; i < 3; i++) mitVar.push(() => i);
for (let j = 0; j < 3; j++) mitLet.push(() => j);
console.log(mitVar.map((f) => f()));  // [3, 3, 3]
console.log(mitLet.map((f) => f()));  // [0, 1, 2]

Siehe auch: Lambda-Ausdruck, Higher-Order-Funktion, Callback, Kapselung