Zuletzt aktualisiert am 16.12.2025 5 Minuten Lesezeit

Closure

Eine Closure (deutsch: Funktionsabschluss) ist ein fundamentales Konzept in der Programmierung, bei dem eine Funktion zusammen mit ihrer lexikalischen Umgebung gespeichert wird. Das bedeutet: Eine innere Funktion behält Zugriff auf die Variablen ihrer äußeren Funktion – auch nachdem diese äußere Funktion bereits beendet wurde. Closures ermöglichen private Variablen, Zustandsspeicherung und elegante Programmiermuster.

Wie Closures funktionieren

Closures basieren auf dem Prinzip des lexikalischen Scopings (auch statisches Scoping genannt). Bei lexikalischem Scoping wird die Sichtbarkeit von Variablen durch die Struktur des Quellcodes bestimmt – nicht durch den Ort des Funktionsaufrufs zur Laufzeit. Wenn eine innere Funktion auf Variablen aus ihrer umgebenden Funktion zugreift, entsteht eine Closure.

Der entscheidende Mechanismus: Wenn die innere Funktion zurückgegeben oder an anderer Stelle gespeichert wird, bleiben alle referenzierten Variablen aus dem äußeren Scope erhalten. Die Laufzeitumgebung verhindert, dass diese Variablen vom Garbage Collector entfernt werden, solange die Closure existiert.

Closures in JavaScript

JavaScript ist die Sprache, in der Closures am häufigsten verwendet werden. Das folgende Beispiel zeigt das Grundprinzip:

function createCounter() {
    let count = 0;  // Private Variable

    return function() {
        count++;
        return count;
    };
}

const counter = createCounter();
console.log(counter());  // Ausgabe: 1
console.log(counter());  // Ausgabe: 2
console.log(counter());  // Ausgabe: 3

Die Variable count ist von außen nicht zugänglich – sie ist effektiv privat. Nur die zurückgegebene Funktion kann auf sie zugreifen und sie verändern. Jeder Aufruf von createCounter() erzeugt eine neue, unabhängige Closure mit eigenem count.

Factory-Funktionen mit Closures

Closures ermöglichen elegante Factory-Funktionen, die spezialisierte Funktionen erzeugen:

function createMultiplier(factor) {
    return function(number) {
        return number * factor;
    };
}

const double = createMultiplier(2);
const triple = createMultiplier(3);

console.log(double(5));  // Ausgabe: 10
console.log(triple(5));  // Ausgabe: 15

Jede zurückgegebene Funktion "erinnert" sich an ihren eigenen factor-Wert. Die Closures double und triple sind völlig unabhängig voneinander.

Closures in Python

Python unterstützt Closures ebenfalls. Für das Verändern von Variablen aus dem äußeren Scope wird das Schlüsselwort nonlocal benötigt:

def create_counter():
    count = 0

    def counter():
        nonlocal count  # Erlaubt Modifikation der äußeren Variable
        count += 1
        return count

    return counter

zaehler = create_counter()
print(zaehler())  # Ausgabe: 1
print(zaehler())  # Ausgabe: 2

Ohne nonlocal würde Python eine neue lokale Variable erstellen, anstatt die äußere zu modifizieren. Python bietet mit dem Attribut __closure__ auch die Möglichkeit, die eingefangenen Variablen einer Closure zu inspizieren.

Typische Anwendungsfälle

Closures sind in der modernen Softwareentwicklung allgegenwärtig. Sie bilden die Grundlage für viele wichtige Programmiermuster und -techniken.

Event Handler und Callbacks

Bei der ereignisgesteuerten Programmierung müssen Callback-Funktionen oft auf Kontextvariablen zugreifen:

function setupClickHandler(buttonId, message) {
    document.getElementById(buttonId).addEventListener('click', function() {
        // Die Closure hat Zugriff auf 'message'
        alert(message);
    });
}

setupClickHandler('btn1', 'Button 1 wurde geklickt!');
setupClickHandler('btn2', 'Button 2 wurde geklickt!');

Das Module Pattern

Closures ermöglichen echte Datenkapselung in JavaScript – ein Muster, das vor ES6-Modulen weit verbreitet war:

const bankAccount = (function() {
    let balance = 0;  // Private Variable

    return {
        deposit: function(amount) {
            if (amount > 0) balance += amount;
        },
        withdraw: function(amount) {
            if (amount > 0 && balance >= amount) {
                balance -= amount;
                return true;
            }
            return false;
        },
        getBalance: function() {
            return balance;
        }
    };
})();

bankAccount.deposit(100);
console.log(bankAccount.getBalance());  // Ausgabe: 100
console.log(bankAccount.balance);       // Ausgabe: undefined (nicht zugänglich)

Currying und Partial Application

Closures sind die Grundlage für Currying – die Umwandlung einer Funktion mit mehreren Parametern in eine Kette von Funktionen mit jeweils einem Parameter:

function curry(fn) {
    return function(a) {
        return function(b) {
            return fn(a, b);
        };
    };
}

const add = (a, b) => a + b;
const curriedAdd = curry(add);

const add5 = curriedAdd(5);
console.log(add5(3));  // Ausgabe: 8

Debouncing und Throttling

Performance-Optimierungen wie Debouncing nutzen Closures zur Zustandsspeicherung:

function debounce(fn, delay) {
    let timeoutId;

    return function(...args) {
        clearTimeout(timeoutId);
        timeoutId = setTimeout(() => fn.apply(this, args), delay);
    };
}

const debouncedSearch = debounce(searchFunction, 300);

Vorteile von Closures

  • Datenkapselung: Variablen können wirklich privat gehalten werden – ohne Klassen oder spezielle Sprachkonstrukte
  • Zustandsspeicherung: Funktionen können Zustand zwischen Aufrufen bewahren, ohne globale Variablen zu nutzen
  • Vermeidung von Namespace-Konflikten: Private Scopes verhindern Namenskollisionen in großen Projekten
  • Funktionale Programmierung: Closures ermöglichen Higher-Order Functions und funktionale Muster
  • Flexible APIs: Factory-Funktionen können spezialisierte Funktionen erzeugen

Häufige Fallstricke

Memory Leaks

Da Closures Referenzen auf Variablen halten, können sie unbeabsichtigt Speicher belegen. Große Objekte, die von einer Closure referenziert werden, können nicht vom Garbage Collector freigegeben werden:

// Problematisch: largeData bleibt im Speicher
function createProcessor() {
    const largeData = new Array(1000000).fill('data');

    return function() {
        console.log(largeData[0]);
    };
}

// Besser: Nur benötigte Werte erfassen
function createProcessor() {
    const largeData = new Array(1000000).fill('data');
    const needed = largeData[0];  // Nur den benötigten Wert extrahieren

    return function() {
        console.log(needed);
    };
}

Closures in Schleifen

Ein klassischer Fehler in JavaScript ist das unbeabsichtigte Teilen von Variablen in Schleifen:

// FALSCH: Alle Callbacks referenzieren dieselbe Variable
for (var i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(i);  // Gibt 5x "5" aus
    }, 100);
}

// RICHTIG: Mit let wird pro Iteration eine neue Variable erstellt
for (let i = 0; i < 5; i++) {
    setTimeout(function() {
        console.log(i);  // Gibt 0, 1, 2, 3, 4 aus
    }, 100);
}

Mit var teilen alle Closures dieselbe Variable. Mit let wird für jede Schleifeniteration eine neue Bindung erstellt – jede Closure hat ihre eigene Kopie von i.

Closures vs. normale Funktionen

Eigenschaft Normale Funktion Closure
Zustandsspeicherung Nur über globale Variablen Über eingefangene Variablen
Datenkapselung Keine echte Privatsphäre Echte private Variablen
Speicherverbrauch Freigabe nach Ausführung Variablen bleiben erhalten
Aufrufverhalten Gleiche Eingabe → gleiche Ausgabe Kann bei gleicher Eingabe unterschiedliche Ausgaben liefern

Closures in der IT-Ausbildung

Das Verständnis von Closures ist besonders wichtig für angehende Fachinformatiker für Anwendungsentwicklung. Closures begegnen dir in der täglichen Arbeit mit JavaScript-Frameworks wie React, Vue oder Angular, bei der Implementierung von Callbacks und Event Handlern sowie beim Verständnis moderner funktionaler Programmiermuster.

Verwandte Konzepte sind die Kapselung in der OOP, die ähnliche Ziele mit anderen Mitteln erreicht, sowie Callbacks und anonyme Funktionen.

Quellen und weiterführende Links