Master the JavaScript Interview: Was ist ein Closure?

„Master the JavaScript Interview“ ist eine Serie von Beiträgen, die Kandidaten auf häufige Fragen vorbereiten sollen, die ihnen bei einer Bewerbung für eine JavaScript-Stelle auf mittlerer bis höherer Ebene begegnen können. Dies sind Fragen, die ich häufig in echten Vorstellungsgesprächen verwende.

Ich beginne die Serie mit der $40k-Frage. Wenn Sie diese Frage falsch beantworten, besteht eine gute Chance, dass Sie nicht eingestellt werden. Wenn Sie doch eingestellt werden, ist die Wahrscheinlichkeit groß, dass Sie als Junior-Entwickler eingestellt werden, unabhängig davon, wie lange Sie schon als Software-Entwickler arbeiten. Im Durchschnitt bekommen Junior-Entwickler $40k/Jahr weniger als erfahrenere Software-Ingenieure.

Closures sind wichtig, weil sie kontrollieren, was in einer bestimmten Funktion im Gültigkeitsbereich ist und was nicht, zusammen mit den Variablen, die zwischen Geschwister-Funktionen im gleichen enthaltenden Bereich geteilt werden. Zu verstehen, wie sich Variablen und Funktionen zueinander verhalten, ist entscheidend, um zu verstehen, was in Ihrem Code vor sich geht, sowohl in funktionalen als auch in objektorientierten Programmierstilen.

Der Grund, warum das Fehlen dieser Frage in einem Vorstellungsgespräch so nachteilig ist, ist, dass Missverständnisse darüber, wie Closures funktionieren, eine ziemlich klare rote Fahne sind, die einen Mangel an tiefgreifender Erfahrung offenbaren kann, nicht nur in JavaScript, sondern in jeder Sprache, die viel auf Closures setzt (Haskell, C#, Python, etc…).

Codieren in JavaScript ohne ein Verständnis von Closures ist wie der Versuch, Englisch ohne ein Verständnis der Grammatikregeln zu sprechen – Sie können vielleicht Ihre Ideen rüberbringen, aber wahrscheinlich ein bisschen unbeholfen.

Sie werden auch anfällig für Missverständnisse sein, wenn Sie versuchen zu verstehen, was jemand anderes geschrieben hat.

Sie sollten nicht nur wissen, was eine Closure ist, sondern auch, warum sie wichtig ist, und mehrere mögliche Anwendungsfälle für Closures leicht beantworten können.

Closures werden in JavaScript häufig für den Schutz von Objektdaten, in Event-Handlern und Callback-Funktionen sowie in partiellen Anwendungen, Currying und anderen funktionalen Programmiermustern verwendet.

Wenn Sie diese Frage nicht beantworten können, könnte Sie das den Job oder ~$40k/Jahr kosten.

Seien Sie auf eine kurze Nachbereitung vorbereitet: „Können Sie zwei häufige Anwendungen für Closures nennen?“

Was ist eine Closure?

Eine Closure ist die Kombination einer Funktion, die mit Referenzen auf ihren umgebenden Zustand (die lexikalische Umgebung) gebündelt (eingeschlossen) wird. Mit anderen Worten, eine Closure ermöglicht den Zugriff auf den Bereich einer äußeren Funktion von einer inneren Funktion aus. In JavaScript werden Closures bei jeder Funktionserstellung erstellt.

Um eine Closure zu verwenden, definieren Sie eine Funktion innerhalb einer anderen Funktion und exponieren sie. Um eine Funktion freizugeben, geben Sie sie zurück oder übergeben sie an eine andere Funktion.

Die innere Funktion hat Zugriff auf die Variablen im äußeren Funktionsbereich, auch nachdem die äußere Funktion zurückgekehrt ist.

Verwendung von Closures (Beispiele)

Unter anderem werden Closures häufig verwendet, um Objekten Datenschutz zu geben. Datenschutz ist eine wesentliche Eigenschaft, die uns hilft, auf eine Schnittstelle und nicht auf eine Implementierung zu programmieren. Dies ist ein wichtiges Konzept, das uns hilft, robustere Software zu bauen, da sich Implementierungsdetails mit größerer Wahrscheinlichkeit ändern als Schnittstellenverträge.

„Program to an interface, not an implementation.“
Design Patterns: Elements of Reusable Object Oriented Software

In JavaScript sind Closures der primäre Mechanismus, um Datenschutz zu ermöglichen. Wenn Sie Closures für den Datenschutz verwenden, sind die eingeschlossenen Variablen nur innerhalb der enthaltenden (äußeren) Funktion im Gültigkeitsbereich. Sie können nur über die privilegierten Methoden des Objekts auf die Daten von außerhalb des Bereichs zugreifen. In JavaScript ist jede exponierte Methode, die innerhalb des Gültigkeitsbereichs der Closure definiert ist, privilegiert. Ein Beispiel:

Spielen Sie damit in JSBin. (Wenn Sie keine Ausgabe sehen, kopieren Sie diesen HTML-Code und fügen Sie ihn in das HTML-Fenster ein.)

Im obigen Beispiel ist die Methode `.get()` innerhalb des Bereichs von `getSecret()` definiert, was ihr Zugriff auf alle Variablen von `getSecret()` gibt und sie zu einer privilegierten Methode macht. In diesem Fall ist es der Parameter `secret`.

Objekte sind nicht die einzige Möglichkeit, Datenschutz zu erzeugen. Closures können auch verwendet werden, um zustandsbehaftete Funktionen zu erstellen, deren Rückgabewerte durch ihren internen Zustand beeinflusst werden können, z.B.:

const secret = msg => () => msg;

Verfügbar auf JSBin. (Wird keine Ausgabe angezeigt? Kopieren Sie dieses HTML und fügen Sie es in den HTML-Bereich ein.)

In der funktionalen Programmierung werden Closures häufig für partielles & Currying verwendet. Dazu sind einige Definitionen erforderlich:

Anwendung: Der Prozess der Anwendung einer Funktion auf ihre Argumente, um einen Rückgabewert zu erzeugen.

Partielle Anwendung: Der Prozess der Anwendung einer Funktion auf einige ihrer Argumente. Die teilweise angewandte Funktion wird zur späteren Verwendung zurückgegeben. Die partielle Anwendung fixiert (wendet die Funktion teilweise an) ein oder mehrere Argumente innerhalb der zurückgegebenen Funktion, und die zurückgegebene Funktion nimmt die verbleibenden Parameter als Argumente, um die Anwendung der Funktion zu vervollständigen.

Die partielle Anwendung nutzt den Gültigkeitsbereich von Closures, um Parameter zu fixieren. Sie können eine generische Funktion schreiben, die Argumente teilweise auf die Zielfunktion anwendet. Sie wird die folgende Signatur haben:

partialApply(targetFunction: Function, ...fixedArgs: Any) =>
functionWithFewerParams(...remainingArgs: Any)

Wenn Sie Hilfe beim Lesen der obigen Signatur benötigen, sehen Sie sich Rtype an: Reading Function Signatures.

Sie nimmt eine Funktion, die eine beliebige Anzahl von Argumenten annimmt, gefolgt von Argumenten, die wir teilweise auf die Funktion anwenden wollen, und gibt eine Funktion zurück, die die verbleibenden Argumente annimmt.

Ein Beispiel wird Ihnen helfen. Sagen wir, Sie haben eine Funktion, die zwei Zahlen addiert:

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

Nun wollen Sie eine Funktion, die 10 zu einer beliebigen Zahl addiert. Wir nennen sie `add10()`. Das Ergebnis von `add10(5)` soll `15` sein. Unsere Funktion `partialApply()` kann das bewirken:

const add10 = partialApply(add, 10);
add10(5);

In diesem Beispiel wird das Argument `10` zu einem festen Parameter, der innerhalb des Schließungsbereichs von `add10()` gespeichert wird.

Lassen Sie uns einen Blick auf eine mögliche `partialApply()`-Implementierung werfen:

Verfügbar auf JSBin. (Sie sehen keine Ausgabe? Kopieren Sie dieses HTML und fügen Sie es in den HTML-Bereich ein.)

Wie Sie sehen, wird einfach eine Funktion zurückgegeben, die den Zugriff auf die `fixedArgs`-Argumente beibehält, die an die Funktion `partialApply()` übergeben wurden.

Sie sind dran

Dieser Beitrag enthält einen begleitenden Videobeitrag und Übungsaufgaben für Mitglieder von EricElliottJS.com. Wenn Sie bereits Mitglied sind, melden Sie sich an und üben Sie jetzt.

Wenn Sie noch kein Mitglied sind, melden Sie sich noch heute an.

Explore the Series

  • Was ist ein Closure?
  • Was ist der Unterschied zwischen Klassen- und Prototypenvererbung?
  • Was ist eine reine Funktion?
  • Was ist eine Funktionskomposition?
  • Was ist funktionale Programmierung?
  • Was ist ein Versprechen?
  • Soft Skills

Updates:
Juli 2019 – Geklärte Einleitung, um zu erklären, warum die falsche Beantwortung dieser Frage Sie einen Job oder eine Menge Geld an Gehalt kosten könnte.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.