Cl

Closures in JavaScript

1 Übung

Über Closures

Closures sind ein Programmiermuster in JavaScript, das es ermöglicht, Variablen aus einem äußeren lexikalischen Gültigkeitsbereich innerhalb eines verschachtelten Blocks zu verwenden. JavaScript unterstützt Closures transparent, und sie werden oft verwendet, ohne zu wissen, was sie sind.

// Top-level declarations are global-scope
const dozen = 12;

// Functions create a new function-scope and block-scope.
// Referencing the outer variable here is a closure.
function nDozen(n) {
  return dozen * n;
}

Der Name Closure stammt historisch vom λ-Kalkül ab und wurde durch Scheme populär (Quelle), um die offenen und geschlossenen Variablenbindungen einer Funktion zu bezeichnen.

Gründe für die Verwendung von Closures in JavaScript

  1. Datenschutz / Datenkapselung

    • Anders als in anderen Sprachen gab es 2020 keine Möglichkeit, private Variablen anzugeben. Closures können also verwendet werden, um private Variablen effektiv nachzubilden (es gab einen Vorschlag, eine Notation für private Variablen einzuführen, die möglicherweise bereits Standard ist, wenn du das hier liest).
    // Consider this function:
    
    const saveNumber = (number) => {
      // The saved value is unaccessible by the outer lexical scope.
      const value = number;
    
      // We can provide access to the primitive value with a function, but the original will never change
      return () => value;
    };
    
    // Attempting to set the variable outside of its lexical scope results in an error
    value = 42;
    
  2. Partielle Anwendung

    • Funktionen können Funktionen zurückgeben, und wenn eine zurückgegebene Funktion das Argument der Funktion verwendet, die sie erzeugt hat, ist das ein Beispiel dafür, mit einer Closure eine partielle Anwendung durchzuführen. Manchmal nennt man das Currying einer Funktion.
    // The arguments are applied one-by-one, using closures to arrive at the final result
    function partialBuildUri(scheme) {
      return function (domain) {
        return function (path) {
          return `${scheme}://${domain}/${path}`;
        };
      };
    }
    
    // A function could apply them all at once.
    function buildUri(scheme, domain, path) {
      return partialBuildUri(scheme)(domain)(path);
    }
    
    // Or apply a few to create a flexible system of functions for reuse.
    function buildHttpsExercismUri(path) {
      return partialBuildUri('https')('exercism.org');
    }
    

Lexikalischer Gültigkeitsbereich für Variablen

In jeder Programmiersprache stehen Closures in engem Zusammenhang mit dem Gültigkeitsbereich von Variablen. In JavaScript gibt es drei Arten von lexikalischem Gültigkeitsbereich für Variablen:

  1. Globaler Gültigkeitsbereich: Das sind Variablen, die außerhalb von Funktionen und Blöcken deklariert werden.
  2. Funktionsgültigkeitsbereich: Das sind Variablen, die innerhalb einer Funktion mit dem Schlüsselwort var deklariert werden.
  3. Blockgültigkeitsbereich: Das sind Variablen, die innerhalb eines Blocks ({...}) mit den Schlüsselwörtern let und const deklariert werden.

In der Praxis entsteht eine Closure oft, wenn eine Funktion (oder ein Block) eine Variable aus einem äußeren Gültigkeitsbereich verwendet. In JavaScript wird das transparent unterstützt, sodass Closures oft verwendet werden, ohne dass ausdrücklich darauf verwiesen wird.

Funktionsgültigkeitsbereich

Das Schlüsselwort var definiert eine Variable mit Funktionsgültigkeitsbereich. Das bedeutet, dass mit var definierte Variablen überall in der Funktion verfügbar sind, in der sie definiert wurden, und in jedem verschachtelten lexikalischen Gültigkeitsbereich (sei es Funktion oder Block).

{
  var five = 5;
}

// This will succeed because 'five' exists in the same scope
var tenTimes = five * 10;

Blockgültigkeitsbereich

Die Schlüsselwörter let und const definieren Variablen mit Blockgültigkeitsbereich. let definiert eine veränderbare Variable, deren Wert mehrmals gesetzt werden kann und die definiert, aber nicht initialisiert werden kann. const definiert eine Variable, die initialisiert werden muss, wenn sie definiert wird, und deren Wert sich danach nicht ändern darf. Wenn die const-Variable auf einen primitiven Wert gesetzt wird, darf sie nicht verändert werden. Wenn die const-Variable auf einen Referenzwert gesetzt wird, wie ein Array oder Objekt, darf sich die Referenz nicht ändern, aber der Inhalt des Arrays kann verändert werden.

Schauen wir uns diesen Block an:

// 'two' is defined at the top-level, therefore available to the global-scope
const two = 2;

{
  // This succeeds, as 'two' is available from the outer lexical scope
  const oneLess = two - 1;
}

// This throws an error because oneLess is not defined outside of the previous inner lexical scope
console.log(oneLess);

Wir können geschweifte Klammern ({...}) zwar beliebig verwenden, um Blöcke zu erzeugen, aber meistens begegnen sie uns im Zusammenhang mit if-Anweisungen, Funktionen und Klassen.

const PI = 3.14;

// This function uses a closure for the value of PI (π)
function areaOfCircle(radius) {
  return PI * radius * radius;
}
Über GitHub bearbeiten Der Link öffnet sich in einem neuen Fenster oder Tab

Lerne Closures