- Lernen
- Informatik & Informationswissenschaften
- Programmierung
- JavaScript – DOM, Ereignisse und asynchroner Code
- Funktionen und Closures in JavaScript
Funktionen und Closures in JavaScript verstehen
return zurück. Bestimme anhand von Blockgültigkeitsbereich, Funktionsgültigkeitsbereich und globalem Gültigkeitsbereich, wo eine Variable verwendet werden kann. Gib Funktionen mit Closures ein eigenes Gedächtnis und übergib Funktionen als Callbacks an andere Funktionen, um flexiblen Code mit Funktionen höherer Ordnung zu schreiben.AnfängerEinheit 3 von 9 in Kurs: JavaScript – DOM, Ereignisse und asynchroner Code
Was du lernst
- Fasse ein wiederverwendbares Stück Code als Funktion zusammen, rufe es mit Argumenten auf und wähle zwischen Funktionsdeklaration, Funktionsausdruck und Pfeilfunktion.
- Schreibe eine Funktionsdeklaration und rufe die Funktion aufDefiniere mit dem Schlüsselwort
functioneine benannte Funktion, rufe sie auf und erkläre, warum Funktionen Code kürzer, übersichtlicher und leichter änderbar machen. - Speichere eine Funktion mit einem Funktionsausdruck in einer VariablenBehandle Funktionen als Werte: Erstelle einen Funktionsausdruck, weise ihn einer Variablen zu und erkläre, wie er sich bei Hoisting und Benennung von einer Deklaration unterscheidet.
- Schreibe PfeilfunktionenNutze die kurze Pfeilsyntax, erkenne, wann eine Pfeilfunktion automatisch einen Wert zurückgibt, und erkläre, wie sie sich von Funktionen unterscheidet, die mit
functiongeschrieben werden.
- Schreibe eine Funktionsdeklaration und rufe die Funktion auf
- Gestalte, was in eine Funktion hineingeht und was herauskommt: Ordne Argumente Parametern zu, lege Standardwerte fest, nimm beliebig viele Argumente entgegen, gib Ergebnisse zurück und verfolge ineinander verschachtelte Aufrufe.
- Ordne Argumente den Parametern zuErkläre, wie die Werte eines Aufrufs zu den Parametern der Funktion gelangen, was bei zu wenigen oder zu vielen Argumenten geschieht und welche Daten des aufrufenden Codes eine Funktion ändern kann.
- Lege Standardwerte fest und nimm beliebig viele Argumente entgegenGib Parametern Standardwerte, sammle beliebig viele Argumente mit einem Restparameter und entpacke ein Array in einzelne Argumente.
- Gib Ergebnisse aus einer Funktion zurückGib mit
returneinen Wert zurück, verwende das Ergebnis im weiteren Code und unterscheide die Rückgabe eines Werts von seiner Ausgabe oder einer Änderung außerhalb der Funktion. - Verfolge Funktionsaufrufe im AufrufstapelVerfolge die Reihenfolge, in der verschachtelte Aufrufe ausgeführt werden und zurückkehren, und schreibe eine einfache rekursive Funktion mit einem Basisfall.
- Ordne Argumente den Parametern zu
- Bestimme mithilfe der Regeln für Blockgültigkeitsbereich, Funktionsgültigkeitsbereich und globalen Gültigkeitsbereich sowie für Funktionen innerhalb anderer Funktionen, wo eine Variable sichtbar ist.
- Unterscheide Blockgültigkeitsbereich, Funktionsgültigkeitsbereich und globalen GültigkeitsbereichErkläre den Gültigkeitsbereich einer mit
let,constodervardeklarierten Variablen und nutze lokale Variablen, um Funktionen voneinander unabhängig zu halten. - Bestimme, auf welche Variable ein Name verweistVerfolge die Gültigkeitsbereichskette, um die Variable hinter einem Namen zu finden, erkenne Verdeckung und erkläre Hoisting und die zeitliche Totzone.
- Unterscheide Blockgültigkeitsbereich, Funktionsgültigkeitsbereich und globalen Gültigkeitsbereich
- Erkläre, wie eine Funktion nach dem Ende der äußeren Funktion Zugriff auf die sie umgebenden Variablen behält, und nutze dies, um Funktionsfabriken und privaten Zustand zu erstellen.
- Erkläre, was eine Closure behältBeschreibe, wie eine Funktion Zugriff auf die Variablen des Gültigkeitsbereichs behält, in dem sie erzeugt wurde, selbst nachdem die äußere Funktion zurückgekehrt ist.
- Nutze Closures für Funktionsfabriken und privaten ZustandErstelle Funktionsfabriken, halte Daten hinter Funktionen privat und vermeide den klassischen Closure-Fehler in einer Schleife.
- Erkläre, was eine Closure behält
- Nutze Funktionen als Werte: Übergib sie als Callbacks an andere Funktionen, nutze und schreibe Funktionen höherer Ordnung und erstelle neue Funktionen aus vorhandenen.
- Übergib einer Funktion einen CallbackÜbergib eine Funktion als Argument an eine andere Funktion, schreibe Funktionen, die einen Callback aufrufen, und übergib die Funktion selbst statt ihres Ergebnisses.
- Nutze und schreibe Funktionen höherer OrdnungErkenne Funktionen höherer Ordnung, nutze Arraymethoden, die Callbacks entgegennehmen, und schreibe eine eigene Funktion, die eine Funktion als Eingabe entgegennimmt.
- Erstelle neue Funktionen aus vorhandenen FunktionenSchreibe Funktionen höherer Ordnung, die andere Funktionen umhüllen, kombinieren oder deren Argumente vorbelegen. Nutze Closures, damit sie sich die übergebene Funktion merken.
- Übergib einer Funktion einen Callback
Funktionen und Closures in JavaScript einfach erklärt
1Definiere Funktionen in drei Formen und rufe sie auf
Funktionen machen aus wiederholten Anweisungen benannte Aufgaben. Du wirst drei gebräuchliche Formen lesen und schreiben und dann entscheiden, ob eine Zeile eine Funktion erzeugt, speichert oder aufruft. Kleine Unterschiede in der Syntax sind wichtig: Eine Deklaration ist früh verfügbar, während ein gespeicherter Ausdruck zuerst initialisiert werden muss. Bei einem Pfeilfunktionsrumpf kann die Form darüber entscheiden, ob ein Ergebnis zurückgegeben wird. Diese Unterschiede bereiten dich darauf vor, Funktionen als gewöhnliche Werte weiterzugeben.
1.1 Schreibe eine Funktionsdeklaration und rufe die Funktion auf
Eine Funktion gibt einer Aufgabe einen Namen und speichert die Anweisungen zu ihrer Ausführung. Das Definieren führt diese Anweisungen nicht aus. Ein Aufruf führt sie aus und ein weiterer Aufruf führt sie mit neuen Eingaben erneut aus.
Schreibe die Definition
Eine Deklaration enthält das Schlüsselwort function, einen Namen, runde Klammern für Parameter und geschweifte Klammern für den Rumpf:
function greet(name) {
console.log("Hello, " + name + "!");
}
Hier ist name ein Parameter: ein lokaler Name für die Eingabe, die jeder Aufruf liefert. Der Rumpf verbindet diese Eingabe mit dem umgebenden Text und gibt das Ergebnis aus. Die schließende geschweifte Klammer markiert das Ende der Definition; die Ausführung wird mit der nächsten Anweisung außerhalb fortgesetzt.
Auch eine Funktion ohne Eingaben braucht runde Klammern. Beispielsweise definiert function sayHi() { console.log("Hi"); } eine Aufgabe mit leerer Parameterliste. Die geschweiften Klammern gehören zur Definition; die runden Klammern nach einem Namen stehen sowohl in Definitionen als auch in Aufrufen und haben dort unterschiedliche Aufgaben.
Führe die Aufgabe aus
greet("Amira");
greet("Li");
Der erste Aufruf gibt name den Wert "Amira" und gibt „Hello, Amira!“ aus. Der zweite beginnt einen neuen Aufruf mit name gleich "Li" und gibt „Hello, Li!“ aus. Die Definition wird gemeinsam genutzt; die Eingabe gehört zum jeweiligen Aufruf.
greet allein verweist auf den Funktionswert. Es führt den Rumpf nicht aus. Dieser Unterschied ist wichtig, wenn eine Zeile scheinbar nichts bewirkt: sayHi; liest einen Funktionswert und verwirft ihn, während sayHi(); „Hi“ ausgibt.
Ersetze kopierte Anweisungen
Angenommen, mehrere Berichte benötigen eine Überschrift zwischen Trennlinien:
function printHeading(title) {
console.log("-----");
console.log(title);
console.log("-----");
}
printHeading("Report");
printHeading("Totals");
Der erste Aufruf gibt eine Linie, „Report“ und eine weitere Linie aus. Der zweite gibt denselben Rahmen um „Totals“ aus. Um die Art der Linien zu ändern, bearbeite die beiden Anweisungen zur Linienausgabe in dieser einen Definition. Ohne die Funktion müsste jede kopierte Überschrift einzeln korrigiert werden.
Wähle einen Namen, der beschreibt, was ein Aufruf tut. printHeading beschreibt eine Aktion; isValidEmail benennt eine Ja-Nein-Prüfung. Verwende camelCase, mit einem kleingeschriebenen ersten Wort und großgeschriebenen Anfängen der folgenden Wörter. Verbindet ein vorgeschlagener Name zwei getrennte Aufgaben mit „und“, überlege, jeder Aufgabe eine eigene Funktion zu geben.
Lies Code, der eine Deklaration früh aufruft
Deklarationen werden eingerichtet, bevor der umgebende Code ausgeführt wird. Dieses Verhalten heißt Hoisting:
sayHi();
function sayHi() {
console.log("Hi");
}
Der Aufruf funktioniert innerhalb des Gültigkeitsbereichs der Deklaration, obwohl die geschriebene Definition später folgt. Hoisting führt den Rumpf nicht früher aus; es stellt die Funktion für einen Aufruf bereit.
Prüfe Schreibweise sowie Groß- und Kleinschreibung, wenn ein Aufruf fehlschlägt. Greet() und greet() sind verschiedene Namen. Der Aufruf eines nicht deklarierten greeet() löst einen ReferenceError aus; fehlen die Klammern des Aufrufs, kann der Fehler unbemerkt bleiben, weil das bloße Lesen einer vorhandenen Funktion gültiger Code ist.
Wichtige Erkenntnisse
- Das Definieren einer Funktion speichert Anweisungen; ihr Aufruf führt sie aus.
- Rufe Funktionen mit runden Klammern auf, auch wenn es keine Argumente gibt.
- Eine Deklaration ist innerhalb desselben Gültigkeitsbereichs schon vor ihrer geschriebenen Position verfügbar.
- Benenne eine klare Aufgabe, damit wiederholter Code an einer Stelle geändert werden kann.
1.2 Speichere eine Funktion mit einem Funktionsausdruck in einer Variablen
Funktionen sind Werte. Du kannst eine Funktion in einer Variablen speichern, ihre Referenz kopieren, sie an eine andere Funktion übergeben oder zurückgeben. Ein Funktionsausdruck erzeugt diesen Wert dort, wo ein Ausdruck erwartet wird.
Speichere eine Funktion
const square = function (n) {
return n * n;
};
const answer = square(4);
Der Ausdruck nach = erzeugt eine Funktion. Die Zuweisung speichert sie in square; der spätere Aufruf gibt 16 zurück. Diese Anweisung endet entsprechend der hier verwendeten Formatierungskonvention mit einem Semikolon.
Die Position von function unterscheidet die Formen. Eine als eigenständiges function square(n) { ... } geschriebene Definition ist eine Deklaration. Eine Funktion nach = oder direkt als Argument eines Aufrufs ist ein Ausdruck. Beide gewöhnlichen Funktionsformen können Parameter entgegennehmen und Werte zurückgeben.
Verwende const für eine Funktionsvariable, wenn ihr Wert gleich bleiben soll. Der Aufruf square(5) ist erlaubt; die Zuweisung square = 5; löst einen TypeError aus. Die Konstante schützt die Variable vor dem Ersetzen. Wiederholte Aufrufe verhindert sie nicht.
Speichere eine Funktion oder ihr Ergebnis
const sq = square;
const result = square(3);
sq verweist auf dieselbe Funktion wie square. Der Aufruf sq(3) gibt 9 zurück. result enthält die Zahl 9, die ein Aufruf zurückgegeben hat. Sie kann nicht als Funktion aufgerufen werden. typeof square und typeof sq ergeben "function"; typeof result ergibt "number".
Es hilft, eine Zuweisung von rechts nach links zu lesen: Entscheide zuerst, ob ihre rechte Seite eine Funktion erzeugt, auf eine vorhandene Funktion verweist oder eine Funktion aufruft. Die Variable links erhält diesen Wert. Das Kopieren der Referenz erzeugt keine zweite unabhängige Implementierung.
Warte, bis die Zuweisung ausgeführt wird
Eine Deklaration und ein gespeicherter Ausdruck sind zu unterschiedlichen Zeiten aufrufbar:
| Form | Vor der geschriebenen Definition oder Zuweisung |
|---|---|
function square(n) { return n * n; } | Innerhalb ihres Gültigkeitsbereichs aufrufbar |
const square = function (n) { return n * n; }; | Das Lesen von square löst einen ReferenceError aus |
var square = function (n) { return n * n; }; | square ist undefined; ein Aufruf löst einen TypeError aus |
Bei const oder let kann der Name vor der Initialisierung nicht verwendet werden. Bei var existiert der Name früh, der Funktionswert wird aber erst zugewiesen, wenn die Ausführung den Ausdruck erreicht. Das Hoisting der Variablen bewirkt kein Hoisting der Zuweisung.
Gib einem Ausdruck einen internen Namen
const factorial = function fact(n) {
return n <= 1 ? 1 : n * fact(n - 1);
};
Der äußere Name ist factorial. Der Name fact gehört in die Funktion und ermöglicht ihr, sich selbst aufzurufen; Code außerhalb kann diesen internen Namen nicht direkt verwenden. Der Name des Ausdrucks kann auch Stacktraces leichter lesbar machen. Beispielsweise berechnet factorial(3) 3 mal 2 mal 1 und gibt 6 zurück.
Deklarationen eignen sich gut für die wichtigsten benannten Aufgaben in einem Skript. Ausdrücke passen an Stellen, an denen Code einen Funktionswert benötigt, etwa bei einer Variablenzuweisung oder einem Argument. Die Wahl eines Ausdrucks ändert, wie der Wert erzeugt und gespeichert wird, nicht aber, wie er mit runden Klammern aufgerufen wird.
Wichtige Erkenntnisse
- Ein Funktionsausdruck erzeugt einen Funktionswert innerhalb eines anderen Ausdrucks.
- Die Zuweisung von
squarekopiert eine Funktionsreferenz; die Zuweisung vonsquare(3)speichert das Ergebnis. - Ein in
constgespeicherter Funktionsausdruck ist erst nach der Initialisierung aufrufbar. - Eine Funktionsvariable mit
varenthältundefined, bevor ihre Zuweisung ausgeführt wird. - Ein benannter Ausdruck kann seinen internen Namen für Selbstaufrufe verwenden.
1.3 Schreibe Pfeilfunktionen
Pfeilfunktionen sind Funktionsausdrücke mit einer kürzeren Schreibweise. Ihr Rückgabeverhalten hängt davon ab, was auf den Pfeil folgt. Sieh dir daher den Rumpf an, bevor du entscheidest, was ein Aufruf liefert.
Wähle die Parameterform
const sayHi = () => "hi";
const double = n => n * 2;
const add = (a, b) => a + b;
Ohne Parameter sind leere Klammern erforderlich. Bei einem einfachen Parameter dürfen die Klammern entfallen. Bei zwei oder mehr sind sie erforderlich. Auch ein Standard- oder Restparameter braucht Klammern: (n = 1) => n * 2 und (...nums) => nums.length sind zulässig.
Der Pfeil trennt die Eingaben vom Rumpf. const double = n => n * 2; erzeugt die Funktion und speichert sie; double(6) ruft sie später auf und gibt 12 zurück. Wie jede mit const gespeicherte Funktion aus einem Funktionsausdruck kann double nicht gelesen werden, bevor seine Initialisierungszeile ausgeführt wird.
Gib einen Ausdruck zurück oder schreibe einen Block
| Rumpf | Beispiel | Ergebnis des Aufrufs mit 2 und 3 |
|---|---|---|
| Ausdrucksrumpf | (a, b) => a + b | 5 |
Block mit return | (a, b) => { return a + b; } | 5 |
Block ohne return | (a, b) => { a + b; } | undefined |
Ein Ausdrucksrumpf gibt seinen Ausdruck automatisch zurück. Geschweifte Klammern beginnen einen Block aus Anweisungen. In einem Block gibt das Auswerten eines Ausdrucks ihn nicht an den aufrufenden Code zurück; schreibe return ausdrücklich.
Verwende einen Block, wenn die Aufgabe Zwischenschritte braucht:
const describe = (n) => {
const kind = n % 2 === 0 ? "even" : "odd";
return n + " is " + kind;
};
Für describe(7) ist die Bedingung falsch, sodass kind zu "odd" wird. Die Rückgabe verbindet dann die Zahl und die Wörter zu „7 is odd“. Würdest du diese Rückgabe entfernen, bliebe die lokale Berechnung bestehen, aber der aufrufende Code erhielte undefined.
Gib ein Objektliteral zurück
Ein Objektliteral verwendet ebenfalls geschweifte Klammern. Setze es in runde Klammern, damit der Parser es als Ausdruck behandelt:
const makePoint = (x, y) => ({ x: x, y: y });
makePoint(2, 5) gibt ein Objekt zurück, dessen x gleich 2 und dessen y gleich 5 ist. Ohne die runden Klammern beginnt die erste geschweifte Klammer einen Block. Die Form mit einer Eigenschaft () => { value: 1 } gibt undefined zurück; die ähnliche Form mit zwei Eigenschaften und einem Komma führt zu einem Syntaxfehler. Die runden Klammern ändern, wie der Rumpf gelesen wird.
Kenne die Grenzen der kürzeren Form
Pfeilfunktionen haben kein eigenes this oder arguments und können nicht mit new aufgerufen werden, um Objekte zu konstruieren. Bei einer einfachen Berechnung, die weder this noch arguments verwendet, verhalten sich eine Pfeilfunktion und ein gewöhnlicher Funktionsausdruck gleich. Ersetzt du jede gewöhnliche Funktion durch eine Pfeilfunktion, kann sich Code ändern, der von diesen Eigenschaften abhängt.
Kurze Pfeilfunktionen sind als Callbacks besonders gut lesbar. [1, 2, 3].map(n => n * 10) übergibt eine Funktion, die ein transformiertes Element zurückgibt, und erzeugt [10, 20, 30]. Änderst du sie zu n => { n * 10; }, geht jeder Rückgabewert unbemerkt verloren.
Wichtige Erkenntnisse
- Ein Ausdrucksrumpf einer Pfeilfunktion gibt seinen Ausdruck automatisch zurück.
- Ein Blockrumpf einer Pfeilfunktion braucht ein ausdrückliches
return, um einen berechneten Wert zurückzugeben. - Setze ein Objektliteral, das ein Ausdrucksrumpf zurückgibt, in runde Klammern.
- Leere und mehrere Parameter sowie Standard- und Restparameter brauchen Klammern.
- Pfeilfunktionen haben kein eigenes
thisoderargumentsund können keine Konstruktoren sein.
2Übergib Funktionen Werte und erhalte Ergebnisse zurück
Ein Funktionsaufruf hat eine Eingabe- und eine Ausgabeseite. Ordne Argumente Parametern zu, verarbeite optionale oder flexible Eingaben und verfolge den Wert, der an den aufrufenden Code zurückgegeben wird. Du wirst außerdem lokale Änderungen von Änderungen an einem gemeinsam genutzten Array unterscheiden und verschachtelte Aufrufe verfolgen, während ihre Ausführung pausiert und fortgesetzt wird. Dasselbe Modell aus Aufruf und Rückkehr erklärt einfache Rekursion, bei der mehrere Aufrufe einer Funktion auf das Ende kleinerer Aufrufe warten.
2.1 Ordne Argumente den Parametern zu
Die Parameter einer Funktion geben den von einem Aufruf gelieferten Werten Namen. Um einen Aufruf nachzuvollziehen, ordne zuerst die Eingaben nach ihrer Position zu und verfolge dann die Operationen im Rumpf.
Ordne Positionen und Typen zu
function area(width, height) {
return width * height;
}
area(4, 2.5);
width und height sind Parameter; 4 und 2,5 sind Argumente. Während dieses Aufrufs enthält width den Wert 4 und height den Wert 2,5, sodass das Ergebnis 10 ist. Parameternamen werden nicht mit Variablennamen des aufrufenden Codes abgeglichen. Bei divide(a, b) ändert das Vertauschen von divide(10, 2) zu divide(2, 10) das Ergebnis von 5 auf 0,2.
JavaScript schreibt die Anzahl der Argumente nicht vor. area(4) belässt height bei undefined; die Multiplikation damit ergibt NaN. area(4, 2, 99) gibt 8 zurück, weil dieser Rumpf das dritte Argument nicht verwendet. Eine Funktion kann zusätzliche Argumente sammeln, aber ungenutzte zusätzliche Argumente verursachen nicht automatisch einen Fehler.
Auch die Typen sind wichtig, selbst wenn der Aufruf akzeptiert wird. area("4", 2) gibt 8 zurück, weil die Multiplikation den Text umwandelt. Eine Additionsfunktion verhält sich anders: add("4", 2) gibt „42“ zurück, wenn ihr Rumpf return a + b; lautet. Stellt Text eine Zahl dar, gibt add(Number("4"), 2) den Wert 6 zurück.
Weise einem lokalen Parameter einen neuen Wert zu
Jeder Parameter ist lokal für seinen Aufruf. Weist du ihm eine neue Zahl zu, wird der Variablen des aufrufenden Codes kein neuer Wert zugewiesen:
let score = 5;
function reset(s) {
s = 0;
}
reset(score);
Der Aufruf kopiert den Wert 5 in s. Die Zuweisung ändert s auf 0 und score bleibt 5. Zahlen, Zeichenketten und boolesche Werte folgen dieser Regel der Wertkopie. Code außerhalb kann s nicht direkt lesen; eine verschachtelte Funktion kann über eine Closure Zugriff darauf behalten.
Ändere ein Array über eine kopierte Referenz
Ein Arraywert ist eine Referenz auf ein Array. Beim Übergeben dieses Werts wird die Referenz kopiert, sodass der aufrufende Code und der Parameter auf dasselbe Array zugreifen können:
const list = [1, 2];
function addItem(arr) {
arr.push(3);
}
addItem(list);
list ist nun [1, 2, 3]. Die Funktion hat list keinen neuen Wert zugewiesen; sie hat das Array geändert, auf das beide Namen zugreifen. Eine const-Deklaration verhindert das Ersetzen ihrer gespeicherten Referenz, nicht aber das Ändern des Arrayinhalts.
Vergleiche eine lokale Neuzuweisung:
function clearLocal(arr) {
arr = [];
}
clearLocal(list);
Dadurch verweist nur arr auf ein neues leeres Array. list greift weiterhin auf [1, 2, 3] zu. Frag dich, ob eine Operation ein vorhandenes Array ändert, wie push, oder einem Namen einen anderen Wert zuweist, wie =.
Gib ein neues Array zurück, wenn die Eingabe erhalten bleiben soll
function withItem(arr, item) {
return arr.concat(item);
}
withItem([1, 2], 3) erzeugt [1, 2, 3] als neues Array. Das Eingabearray bleibt [1, 2]. Das macht die Funktion nützlich, wenn der aufrufende Code sowohl die alte als auch die erweiterte Liste benötigt. Mache durch Namen und Verhalten einer Funktion deutlich, welche Änderungen sie an ihrer Eingabe vornehmen soll, damit aufrufender Code sie erwartungsgemäß nutzen kann.
Wichtige Erkenntnisse
- Argumente werden Parametern nach ihrer Position zugeordnet.
- Ein fehlendes Argument liefert
undefined; ungenutzte zusätzliche Argumente sind erlaubt. - Eine Neuzuweisung an einen Parameter weist der Variablen des aufrufenden Codes keinen neuen Wert zu.
- Eine Änderung an einem Array über einen Parameter ändert das gemeinsam genutzte Array.
- Die Rückgabe eines neuen Arrays kann die Eingabe erhalten.
2.2 Lege Standardwerte fest und nimm beliebig viele Argumente entgegen
Standardwerte machen eine Eingabe optional; Restparameter erlauben es einem Aufruf, viele Eingaben zu übergeben. Die Spread-Syntax verbindet ein vorhandenes Array mit einer Funktion, die einzelne Argumente erwartet.
Verwende einen Standardwert nur bei undefined
function greet(name = "friend") {
return "Hello, " + name;
}
Sowohl greet() als auch greet(undefined) geben „Hello, friend“ zurück. greet(null) gibt „Hello, null“ und greet("") gibt „Hello, “ zurück. Ein Standardwert prüft auf undefined, nicht auf jeden Wert, der leer aussieht.
Standardwerte werden ausgewertet, wenn ein Aufruf sie benötigt. Sie dürfen frühere Parameter verwenden: function makeBox(width, height = width) { return width * height; } gibt für makeBox(3) den Wert 9 und für makeBox(3, 4) den Wert 12 zurück. Das ausdrücklich angegebene zweite Argument ersetzt für diesen Aufruf den Standardwert.
Setze erforderliche Eingaben an den Anfang. Bei function total(amount, rate = 0.25) { return amount + amount * rate; } gibt total(80) den Wert 100 und total(80, 0.5) den Wert 120 zurück. Würden die Parameter vertauscht, wäre für den üblichen Aufruf mit Standardsatz total(undefined, 80) nötig.
Älterer Code verwendet möglicherweise level = level || 50;. Das ersetzt auch 0, false und eine leere Zeichenkette, weil sie Falsy-Werte sind. Ein Standardparameter erhält diese Werte: function setVolume(level = 50) { return level; } gibt für setVolume(0) den Wert 0 und für setVolume(undefined) den Wert 50 zurück.
Sammle Argumente mit Rest
function sum(...numbers) {
let total = 0;
for (const n of numbers) {
total += n;
}
return total;
}
sum(1, 2, 3) legt [1, 2, 3] in numbers ab und gibt 6 zurück. sum() übergibt ein leeres Array, sodass die Schleife nichts addiert und 0 zurückgibt. Ein Restparameter ist ein echtes Array und kann direkt für Arraymethoden oder Schleifendurchläufe verwendet werden.
Eine feste Eingabe kann vor Rest stehen: In function log(label, ...values) { console.log(label, values); } gibt log("scores", 7, 9) dem Parameter label die Zeichenkette „scores“ und values das Array [7, 9]. Nur ein Restparameter ist erlaubt und er muss zuletzt stehen; andernfalls kann JavaScript die übrigen Argumente mit dieser Syntax nicht eindeutig zuordnen.
Entfalte Argumente mit Spread
Position von ... | Aufgabe | Beispiel |
|---|---|---|
| Parameterliste der Definition | Übrige Argumente sammeln | function sum(...numbers) { ... } |
| Argumentliste des Aufrufs | Arrayelemente entfalten | sum(...values) |
Math.max(...[3, 7, 2]) erhält drei Zahlen und gibt 7 zurück. Math.max([3, 7, 2]) erhält ein Array und gibt NaN zurück. Die drei Punkte sehen im Code gleich aus, aber die umgebende Syntax zeigt dir, welche Aufgabe sie erfüllen.
Gewöhnliche Funktionen haben auch ein arguments-Objekt, das die an sie übergebenen Argumente enthält. Es ist arrayähnlich und hat indizierte Einträge und eine Länge, ist aber kein echtes Array und hat keine eigenen Methoden map oder filter. Pfeilfunktionen haben kein eigenes arguments. Bevorzuge für neuen Code, der eine flexible Liste von Eingaben benötigt, einen Restparameter.
Wichtige Erkenntnisse
- Standardwerte gelten für fehlende Argumente und ausdrücklich übergebenes
undefined, während 0 undnullerhalten bleiben. - Ein Standardausdruck wird für jeden Aufruf ausgewertet, der ihn benötigt.
- Ein Restparameter sammelt die übrigen Argumente in einem Array und steht zuletzt.
- Spread entfaltet ein Array in einzelne Argumente eines Aufrufs.
- Das ältere
arguments-Objekt ist arrayähnlich; Rest erzeugt ein echtes Array.
2.3 Gib Ergebnisse aus einer Funktion zurück
Ein Rückgabewert ist die Ausgabe, die anderer Code von einem Aufruf erhält. Eine Ausgabe auf dem Bildschirm kann denselben Wert anzeigen, liefert dem aufrufenden Code aber ein anderes Ergebnis, sofern die Funktion ihn nicht auch zurückgibt.
Verwende den Aufruf als Wert
function double(n) {
return n * 2;
}
const x = double(5) + 1;
double(5) gibt 10 zurück, sodass die Zuweisung 10 plus 1 berechnet und 11 speichert. Ein Aufruf kann überall dort stehen, wo ein passender Wert benötigt wird. double(double(3)) erhält zuerst 6 vom inneren Aufruf und gibt dann 12 vom äußeren zurück. Math.round(double(2.3)) verdoppelt auf 4,6 und rundet auf 5.
return beendet auch den aktuellen Aufruf sofort. Eine Wächterklausel (Guard Clause) behandelt einen Sonderfall vor der Hauptarbeit:
function safeDivide(a, b) {
if (b === 0) {
return null;
}
return a / b;
}
safeDivide(6, 0) gibt null zurück und erreicht die Division nie. safeDivide(6, 2) überspringt die Wächterklausel und gibt 3 zurück. Setze die Bedingung vor die Operation, die sie absichert.
Unterscheide Rückgabe und Anzeige
function addLog(a, b) {
console.log(a + b);
}
addLog(2, 3) gibt 5 aus, aber sein Rückgabewert ist undefined. Daher gibt addLog(2, 3) * 2 den Wert 5 aus und wird zu NaN ausgewertet. Eine Funktion, die ihr Ende ohne Rückgabe erreicht oder ein alleinstehendes return; ausführt, gibt undefined zurück. Die Konsolenanzeige ist ein Seiteneffekt, nicht das nutzbare numerische Ergebnis des Aufrufs.
Wenn der aufrufende Code eine Summe benötigt, schreibe return a + b;. Der aufrufende Code kann dann entscheiden, ob er sie ausgibt, speichert oder in einer weiteren Berechnung verwendet. So bleibt die Entscheidung über die Anzeige außerhalb einer wiederverwendbaren Berechnung.
Halte den zurückgegebenen Ausdruck in derselben Zeile
function brokenAdd(a, b) {
return
a + b;
}
JavaScript beendet die return-Anweisung am Zeilenumbruch. Die Funktion gibt undefined zurück; der nachfolgende Ausdruck wird nie erreicht. Beginne bei einem langen Ausdruck diesen oder öffne eine Klammer in der return-Zeile und fahre dann darunter fort.
Fasse mehrere Ergebnisse in einem Wert zusammen
Ein Aufruf gibt einen Wert zurück, aber dieser Wert kann ein Array sein:
function minMax(nums) {
return [Math.min(...nums), Math.max(...nums)];
}
const [low, high] = minMax([4, 9, 1]);
Das zurückgegebene Array ist [1, 9]. Die Destrukturierung weist seinen ersten Eintrag low und seinen zweiten high zu. Es bleibt ein Rückgabewert, der zwei nützliche Ergebnisse enthält.
Eine reine Funktion berechnet ihre Ausgabe aus ihren Argumenten und ändert außerhalb ihrer selbst nichts. double ist rein. Ausgaben, das Aktualisieren einer äußeren Variablen und das Verändern eines Eingabearrays sind Seiteneffekte. Reine Berechnungen lassen sich leicht mit Eingabe-Ausgabe-Beispielen prüfen; Seiteneffekte gehören in klar benannte Funktionen, wo das Programm sichtbare Änderungen benötigt.
Wichtige Erkenntnisse
returnliefert den Wert des Aufrufs und beendet den aktuellen Aufruf.- Eine bloße Ausgabe belässt den Rückgabewert der Funktion bei
undefined. - Beginne den zurückgegebenen Ausdruck in der
return-Zeile. - Ein zurückgegebenes Array kann mehrere Ergebnisse enthalten.
- Reine Funktionen hängen von ihren Argumenten ab und nehmen keine Änderungen außerhalb vor.
2.4 Verfolge Funktionsaufrufe im Aufrufstapel
Wenn eine Funktion eine andere aufruft, pausiert die aufrufende Funktion, bis dieser Aufruf zurückkehrt. Der Aufrufstapel hält die unerledigte Arbeit fest, damit die Ausführung an der richtigen Stelle fortgesetzt werden kann.
Füge Stapelrahmen hinzu und entferne sie
Jeder aktive Aufruf hat einen Stapelrahmen (Stack Frame), der seine Parameter, lokalen Variablen und die Stelle für die Rückkehr enthält. Ein neuer Aufruf kommt oben auf den Stapel; eine Rückkehr entfernt diesen obersten Rahmen.
function square(n) {
return n * n;
}
function sumOfSquares(a, b) {
return square(a) + square(b);
}
sumOfSquares(3, 4);
Zuerst beginnt sumOfSquares mit a gleich 3 und b gleich 4. Die Funktion ruft square(3) auf, das 9 zurückgibt und endet. Dann wird square(4) ausgeführt und gibt 16 zurück. Die pausierte Addition kann nun als 9 plus 16 abgeschlossen werden und sumOfSquares gibt 25 zurück. Die beiden Aufrufe von square überschneiden sich in diesem Ablauf nicht.
Jeder Aufruf erhält neue Parameter und lokale Variablen. Zwei Aufrufe derselben Funktion verwenden den lokalen numerischen Zustand eines früheren Aufrufs nicht erneut. Selbst wenn eine Funktion sich selbst aufruft, hat der neue Aufruf seinen eigenen Rahmen.
Verkleinere ein Problem mit Rekursion
Eine rekursive Funktion ruft sich selbst auf. Ein Basisfall endet ohne weiteren Selbstaufruf; ein rekursiver Fall macht einen Schritt auf diesen Basisfall zu.
function factorial(n) {
if (n <= 1) {
return 1;
}
return n * factorial(n - 1);
}
Für nicht negative ganzzahlige Eingaben multipliziert dies die Ganzzahlen abwärts bis 1. Verfolge factorial(4) in zwei Richtungen:
factorial(4)wartet auffactorial(3).- Dieser Aufruf wartet auf
factorial(2). - Dieser Aufruf wartet auf
factorial(1). - Der Basisfall gibt 1 zurück.
- Die wartenden Aufrufe geben 2, dann 6 und dann 24 zurück.
Die Multiplikation im Aufruf mit n gleich 4 erfolgt, nachdem der kleinere Aufruf zurückgekehrt ist. Sein eigenes n ist während des Wartens 4 geblieben.
Ein Basisfall muss erreichbar sein. Nur n === 1 zu verwenden, schlägt bei einer Starteingabe von 0 fehl, wenn jeder rekursive Aufruf 1 abzieht: Die Werte werden negativ und erreichen 1 nie. n <= 1 fängt sowohl 0 als auch 1 ab. Ohne einen Pfad zum Anhalten erschöpfen die wiederholten Aufrufe den Stapel. Chrome und Node.js melden „RangeError: Maximum call stack size exceeded“; Firefox verwendet „InternalError: too much recursion“.
Erkenne eine kleinere Kopie derselben Aufgabe
function countItems(list) {
let count = 0;
for (const item of list) {
if (Array.isArray(item)) {
count += countItems(item);
} else {
count += 1;
}
}
return count;
}
countItems([1, [2, 3], [4, [5]]]) gibt 5 zurück. Jedes verschachtelte Array stellt dieselbe Zählfrage für eine kleinere Liste. Für eine einfache Fakultätsberechnung eignet sich auch eine Schleife; Rekursion ist besonders nützlich, wenn die Daten selbst verschachtelt sind.
Schlägt ein Aufruf fehl, lies den Stacktrace vom letzten Aufruf ganz oben aus. Die folgenden Einträge zeigen, welche noch nicht abgeschlossenen Aufrufe dorthin geführt haben. Wiederholte Einträge für eine Funktion können eine Rekursion zeigen, die nicht angehalten hat.
Wichtige Erkenntnisse
- Der Aufrufstapel verfolgt nicht abgeschlossene Aufrufe; Rückgaben entfernen den jeweils letzten Rahmen.
- Jeder Aufruf hat eigene Parameter und lokale Variablen.
- Rekursion braucht einen Fall zum Anhalten und Schritte auf diesen Fall zu.
- Rekursive Ergebnisse werden in umgekehrter Reihenfolge durch die wartenden Aufrufe zurückgegeben.
- Ein Stacktrace zeigt den fehlgeschlagenen Aufruf und die Aufrufe, die dazu geführt haben.
- Verschachtelte Daten können kleinere Instanzen derselben Aufgabe enthalten.
3Erkläre, wo du eine Variable verwenden kannst
Variablennamen haben innerhalb von Gültigkeitsbereichen eine Bedeutung. Block- und Funktionsgrenzen sowie die Stelle, an der eine Funktion definiert ist, bestimmen, auf welche Deklarationen sie zugreifen kann. Du wirst diese Grenzen verfolgen, um einen Wert oder Fehler vorherzusagen, und dann Verdeckung von der Aktualisierung einer äußeren Variablen unterscheiden. Hoisting und die zeitliche Totzone erklären, warum ein Name bereits registriert sein kann, bevor die Ausführung seine Zeile erreicht, und dennoch nicht verwendbar ist.
3.1 Unterscheide Blockgültigkeitsbereich, Funktionsgültigkeitsbereich und globalen Gültigkeitsbereich
Der Gültigkeitsbereich einer Variablen ist der Bereich, in dem ihr Name verwendet werden kann. Gültigkeitsbereiche ermöglichen es Funktionen, ihre Arbeitsdaten getrennt zu halten und zugleich Eingaben und Werte aus dem umgebenden Code zu verwenden.
Ziehe Grenzen um Deklarationen
let und const haben einen Blockgültigkeitsbereich. Ein Block ist ein Bereich innerhalb geschweifter Klammern, etwa ein if-Rumpf, ein Schleifenrumpf oder ein Funktionsrumpf:
if (true) {
const msg = "hi";
console.log(msg);
}
Die Ausgabe funktioniert innerhalb des Blocks. Fügst du console.log(msg); danach hinzu, löst dies einen ReferenceError aus, weil dieser äußere Code nicht auf die Deklaration zugreifen kann. Eine andere äußere Deklaration mit demselben Namen wäre eine andere Variable.
Parameter und Variablen innerhalb einer Funktion sind lokal für diese Funktion. In function f() { let temp = 1; } kann Code außerhalb temp nicht lesen. Zwei Funktionen können jeweils ein lokales total haben, ohne es zu teilen. Jeder Aufruf beginnt mit neuen lokalen Variablen; eine zurückgegebene verschachtelte Funktion kann den Zugriff später über eine Closure erhalten.
Lies ältere var-Deklarationen
| Deklaration | Grenze |
|---|---|
let oder const innerhalb eines Blocks | Dieser Block |
var innerhalb einer Funktion | Die umschließende Funktion, auch wenn die Deklaration in einem inneren Block steht |
| Deklaration auf oberster Ebene in einem gewöhnlichen Skript | Der globale Gültigkeitsbereich des Skripts |
| Deklaration auf oberster Ebene in einem Modul | Dieses Modul |
function test() {
if (true) {
var x = 1;
}
return x;
}
test() gibt 1 zurück, weil var die Grenze des if-Blocks ignoriert. Ersetzt du es durch let x = 1;, schlägt die Rückgabe fehl: Das x des Blocks ist dort nicht verfügbar. Ebenso hält for (let i = 0; i < 3; i++) {} das i innerhalb der Schleife, während ein var i nach der Schleife in seiner umschließenden Funktion oder seinem Skript verfügbar bleibt und 3 enthält.
Suche von der geschriebenen Position der Funktion aus nach außen
Gültigkeitsbereiche sind verschachtelt. Eine innere Funktion kann Namen in ihren umschließenden Gültigkeitsbereichen verwenden, aber äußerer Code kann nicht nach innen in die lokalen Variablen einer inneren Funktion suchen. Das ist der lexikalische Gültigkeitsbereich: Die Stelle, an der der Code geschrieben steht, bestimmt die verfügbaren Namen.
const level = "global";
function show() {
return level;
}
function run() {
const level = "local";
return show();
}
run() gibt „global“ zurück. show wurde außerhalb von run definiert, sodass sein umschließender Gültigkeitsbereich das äußere level enthält. Der Aufruf innerhalb von run gibt der Funktion keinen Zugriff auf das lokale level des aufrufenden Codes.
Setze gemeinsam genutzten Zustand bewusst ein
Eine Variable auf oberster Ebene in einem gewöhnlichen Skript ist global und für Funktionen innerhalb dieses Skripts erreichbar. Gemeinsam genutzte globale Variablen können dazu führen, dass unabhängige Aufgaben einander beeinflussen; auch Skripte auf derselben Seite können wegen gleicher Namen in Konflikt geraten. Die Übergabe von Eingaben und die Rückgabe von Ausgaben machen Abhängigkeiten sichtbar.
Deklariere jede Variable. Im strikten Modus löst count = 5; einen ReferenceError aus, wenn keine erreichbare Deklaration existiert. Ohne strikten Modus kann eine solche Zuweisung versehentlich eine globale Variable erzeugen. Ein Skript kann den strikten Modus mit "use strict"; an seinem Anfang aktivieren; Module aktivieren ihn automatisch. Bevorzuge const für Werte, denen kein neuer Wert zugewiesen wird, und let, wenn eine Neuzuweisung nötig ist.
Wichtige Erkenntnisse
letundconstbeachten Blockgrenzen;varbeachtet die Grenze der umschließenden Funktion.- Funktionsparameter und lokale Variablen sind für Code außerhalb nicht verfügbar.
- Der lexikalische Gültigkeitsbereich richtet sich danach, wo eine Funktion definiert ist, nicht danach, wo sie aufgerufen wird.
- Variablen auf oberster Ebene eines Moduls gehören zum Modul.
- Deklariere Namen ausdrücklich, um versehentliche globale Zuweisungen zu verhindern.
3.2 Bestimme, auf welche Variable ein Name verweist
Derselbe Name kann in mehreren Gültigkeitsbereichen vorkommen. JavaScript findet die passende Deklaration, indem es vom aktuellen Code aus nach außen sucht und beim ersten Treffer anhält.
Verfolge die Gültigkeitsbereichskette
let x = 1;
function f() {
let x = 2;
return x;
}
f() gibt 2 zurück. Die lokale Deklaration verdeckt das äußere x, sodass die Suche innerhalb von f endet. Der äußere Wert bleibt 1. Ein Parameter kann einen Namen auf dieselbe Weise verdecken. Deklariert kein Bereich der Kette einen Namen, löst sein Lesen einen ReferenceError aus.
Eine Zuweisung deklariert keine neue Variable. Bei let count = 0; function add() { count = count + 1; } findet add die äußere Deklaration und ändert sie. Das Einfügen von let ändert die Bedeutung: Es erzeugt einen neuen lokalen Namen, der genau den Wert verdecken kann, den du lesen wolltest.
Unterscheide Registrierung und Initialisierung
Hoisting beschreibt, wie Deklarationen registriert werden, bevor ihr Gültigkeitsbereich ausgeführt wird. Ihr Verhalten zu diesem frühen Zeitpunkt unterscheidet sich:
| Deklaration | Vor ihrer Initialisierungszeile |
|---|---|
| Funktionsdeklaration | Ihre Funktion ist verfügbar |
var | Ihr Wert ist undefined |
let oder const | Ein Zugriff löst einen ReferenceError aus |
Beispielsweise gibt console.log(a); var a = 5; den Wert undefined aus. Die Zuweisung von 5 hat noch nicht stattgefunden. console.log(b); let b = 5; schlägt dagegen fehl. Der Zeitraum, in dem der lexikalische Name existiert, aber nicht darauf zugegriffen werden kann, heißt zeitliche Totzone, oft mit TDZ abgekürzt.
Verfolge eine Verdeckung vor der Deklarationszeile
let n = 10;
function f() {
console.log(n);
let n = 20;
}
f();
Das innere n verdeckt das äußere im gesamten Funktionsrumpf, auch vor der geschriebenen Deklarationszeile. Bei console.log(n) befindet sich dieser innere Name noch in seiner TDZ, sodass der Aufruf einen ReferenceError auslöst. JavaScript überspringt eine nicht initialisierte lokale Deklaration nicht, um auf den äußeren Wert 10 zurückzugreifen.
Dasselbe Problem tritt bei let count = count + 1; innerhalb von add auf. Die rechte Seite liest das neue lokale count, bevor es initialisiert wurde. Soll ein äußerer Zähler aktualisiert werden, verwende eine Zuweisung ohne neue Deklaration. Soll ein eigener Wert berechnet werden, gib ihm einen anderen Namen und lies den äußeren Zähler ausdrücklich.
Unterscheide Neuzuweisung und Mutation
let und const können denselben Namen nicht erneut im selben Gültigkeitsbereich deklarieren; dies führt zu einem SyntaxError. Ein innerer Gültigkeitsbereich darf einen eigenen Namen deklarieren; das ist Verdeckung. var erlaubt wiederholte Deklarationen in seinem Gültigkeitsbereich, wodurch eine versehentliche Wiederverwendung von Namen schwerer zu erkennen ist.
const verhindert eine Neuzuweisung an seine Variable. Es friert ein Array nicht ein:
const list = [];
list.push(1);
Die in list gespeicherte Referenz bleibt gleich, während sich das Array zu [1] ändert. list = []; würde versuchen, die gespeicherte Referenz zu ersetzen, und fehlschlagen.
Platziere eine Deklaration im kleinsten Gültigkeitsbereich, in dem sie benötigt wird. Verschiedene Namen für verschiedene Aufgaben verringern den Aufwand, Verdeckungen gedanklich zu verfolgen. Eine Initialisierung vor der Verwendung vermeidet Fehler durch die TDZ.
Wichtige Erkenntnisse
- Die Namenssuche endet bei der nächstgelegenen umschließenden Deklaration.
- Eine lokale Deklaration verdeckt einen äußeren Namen schon vor ihrer Initialisierung.
varbeginnt mitundefined;letundconstsind in ihrer TDZ nicht zugänglich.- Eine Zuweisung aktualisiert eine vorhandene Bindung; eine Deklaration erzeugt eine.
constverhindert eine Neuzuweisung, während sich der Inhalt eines Arrays weiterhin ändern kann.- Eine erneute Deklaration im selben Gültigkeitsbereich unterscheidet sich von einer Verdeckung in einem verschachtelten Bereich.
4Gib Funktionen mit Closures ein eigenes Gedächtnis
Eine zurückgegebene Funktion kann Zugriff auf die Variablen um ihre Definition herum behalten. Diese erhaltene Verbindung gibt einem Zähler ein Gedächtnis und ermöglicht es einer Fabrik, Funktionen mit eigenen Einstellungen zu erstellen. Du wirst getrennte Fabrikaufrufe, gemeinsam genutzten Zustand und spätere Änderungen an eingefangenen Variablen verfolgen und anschließend mit denselben Regeln erklären, wie in einer Schleife erzeugte Funktionen arbeiten. Privater Zustand ergibt sich aus dem gewöhnlichen lexikalischen Gültigkeitsbereich, selbst nachdem der äußere Aufruf zurückgekehrt ist.
4.1 Erkläre, was eine Closure behält
Eine Funktion behält eine Verbindung zu dem Gültigkeitsbereich, in dem sie erzeugt wurde. Die Funktion und dieser erhaltene Zugriff bilden eine Closure. Die Verbindung ist besonders nützlich, wenn eine verschachtelte Funktion zurückgegeben und aufgerufen wird, nachdem ihr äußerer Aufruf beendet ist.
Gib einer zurückgegebenen Funktion ein Gedächtnis
function makeCounter() {
let count = 0;
return function () {
count = count + 1;
return count;
};
}
const counter = makeCounter();
Der Aufruf von makeCounter erzeugt count, erzeugt eine innere Funktion und gibt diese Funktion zurück. Den inneren Rumpf führt er noch nicht aus. counter enthält nun den Funktionswert. Sein erster Aufruf ändert das erhaltene count von 0 auf 1 und gibt 1 zurück. Der nächste Aufruf ändert dieselbe Variable auf 2 und gibt 2 zurück.
Der Stapelrahmen des äußeren Aufrufs ist beendet, aber die eingefangene Variable bleibt zugänglich. Eine lokale Variable, die nicht mehr erreichbar verwendet werden kann, kann freigegeben werden; hier benötigt die aufrufbare innere Funktion sie noch. Der Zugriff über die Closure bleibt nach einer Rückkehr erhalten, ohne die Variable global zu machen.
Erzeuge mit getrennten Aufrufen unabhängige Speicher
const a = makeCounter();
const b = makeCounter();
a();
a();
b();
Die Ergebnisse sind 1, 2 und 1. Jeder Fabrikaufruf hat ein eigenes count erzeugt. Die beiden aus getrennten Aufrufen zurückgegebenen Funktionen haben denselben Code, aber unterschiedliche erhaltene Umgebungen.
Das Kopieren einer zurückgegebenen Funktionsreferenz funktioniert anders. Bei const alias = a; verwendet alias() den vorhandenen Zähler von a; es ruft nicht makeCounter auf und erzeugt keine weitere Umgebung.
Behalte Variablen, keine Momentaufnahmen
let greeting = "Hi";
const say = () => greeting;
greeting = "Hello";
say() gibt „Hello“ zurück. Die Closure liest die Variable bei ihrer Ausführung, sodass eine spätere Aktualisierung sichtbar ist. Sie speichert bei ihrer Erzeugung keine eingefrorene Kopie von „Hi“.
Code außerhalb kann nicht direkt auf das lokale count zugreifen und counter.count ist undefined. Nur Code mit Zugriff auf diese lexikalische Umgebung kann die Variable lesen oder aktualisieren. Der Aufruf des Zählers aus einer anderen Funktion ändert nicht, welche Zählervariable er verwendet.
Teile Zustand innerhalb eines äußeren Aufrufs
function makeWallet() {
let balance = 0;
return [
function deposit(n) { balance += n; return balance; },
function getBalance() { return balance; }
];
}
const [deposit, getBalance] = makeWallet();
deposit(50);
deposit(20);
getBalance() gibt 70 zurück, weil beide zurückgegebenen Funktionen im selben Aufruf erzeugt wurden und auf dasselbe balance verweisen. Ein weiterer Aufruf von makeWallet() erzeugt einen eigenen Kontostand.
Wichtige Erkenntnisse
- Eine Closure behält Zugriff auf den Gültigkeitsbereich, in dem ihre Funktion erzeugt wurde.
- Eine eingefangene Variable kann nach der Rückkehr ihres äußeren Aufrufs verwendbar bleiben.
- Getrennte Fabrikaufrufe erzeugen getrennte Umgebungen.
- Closures lesen aktuelle Variablenwerte, keine Momentaufnahmen vom Zeitpunkt ihrer Erzeugung.
- Funktionen aus demselben äußeren Aufruf können privaten Zustand teilen.
4.2 Nutze Closures für Funktionsfabriken und privaten Zustand
Eine Funktionsfabrik nutzt den Zugriff über eine Closure, um Funktionen mit eigenen Einstellungen oder eigenem Zustand zu erzeugen. Der aufrufende Code übergibt die Konfiguration einmal und nutzt die zurückgegebene Funktion danach vielfach.
Konfiguriere eine Funktion mit einem Parameter
function makeMultiplier(factor) {
return (n) => n * factor;
}
const double = makeMultiplier(2);
const triple = makeMultiplier(3);
double(5) gibt 10 und triple(5) gibt 15 zurück. Jede zurückgegebene Pfeilfunktion behält den factor aus ihrem eigenen Fabrikaufruf. Die äußere Funktion konfiguriert das Verhalten; die innere führt die wiederholte Arbeit aus.
Die kompakte Form lautet const makeMultiplier = (factor) => (n) => n * factor;. Zwei Pfeile bedeuten, dass zwei Funktionen erzeugt werden, nicht zwei aufeinanderfolgende Berechnungen mit einer Zahl. makeMultiplier(4)(5) gibt zuerst eine mit 4 konfigurierte Funktion zurück und ruft sie dann mit 5 auf, um 20 zu erhalten.
Setze eine Regel für privaten Zustand durch
function makeLimiter(max) {
let used = 0;
return function () {
if (used >= max) {
return false;
}
used = used + 1;
return true;
};
}
const tryLogin = makeLimiter(3);
Die ersten drei Aufrufe geben true zurück und erhöhen used. Der vierte gibt false zurück, bevor der Wert erhöht wird. used ist lokal für den Fabrikaufruf, sodass Code außerhalb die Variable nicht über diesen Namen zurücksetzen kann. Die zurückgegebene Funktion steuert, welche Änderungen möglich sind. Ein weiterer Begrenzer hätte seine eigene Variable used und seinen eigenen Höchstwert.
Untersuche in Schleifen erzeugte Funktionen
const fns = [];
for (var i = 0; i < 3; i++) {
fns.push(() => i);
}
Die Schleife erzeugt drei Funktionen, aber nur ein var i. Nach der Schleife enthält diese Variable 3. Der Aufruf einer beliebigen gespeicherten Funktion gibt nun 3 zurück, weil jede Closure dieselbe aktuelle Bindung liest. Das Erzeugen einer Funktion wertet ihren Rumpf nicht aus und erstellt keine Momentaufnahme des aktuellen i.
Änderst du den Schleifenkopf zu let i = 0, erhält jeder Schleifendurchlauf eine eigene Bindung. Die gespeicherten Funktionen geben dann 0, 1 und 2 zurück. Derselbe Unterschied erklärt eine verzögerte Ausgabe: Ein setTimeout-Callback, der nach der Schleife var i liest, sieht den Endwert, während die let-Version den Wert jedes Schleifendurchlaufs behält.
Erkenne einen sofort aufgerufenen Ausdruck
Älterer Code erzeugt oft einen privaten Funktionsgültigkeitsbereich und führt die Funktion sofort aus:
(function () {
var hidden = 1;
console.log(hidden);
})();
Dies ist ein sofort aufgerufener Funktionsausdruck, kurz IIFE. Die äußeren Klammern machen daraus einen Funktionsausdruck; die abschließenden Klammern rufen ihn auf. hidden gehört zu dieser Funktion und bleibt dadurch außerhalb des umgebenden globalen Gültigkeitsbereichs. Das Muster ist in Code verbreitet, der vor Deklarationen mit Blockgültigkeitsbereich und Modulen geschrieben wurde.
Der erhaltene Zugriff wirkt sich auch auf den Speicher aus. Eine aufrufbare Closure, die ein großes Array benötigt, hält diese Daten erreichbar. Sind die Funktion und ihre eingefangenen Daten nicht mehr erreichbar, können sie freigegeben werden. Speichere langlebige Closures bewusst, wenn ihr Speicher Teil der Aufgabe ist.
Wichtige Erkenntnisse
- Fabriken geben Funktionen zurück, die durch ihre Argumente konfiguriert sind.
- Private Variablen können über die zurückgegebenen Operationen geändert werden.
- Closures einer
var-Schleife teilen sich eine Bindung; Schleifendurchläufe mitleterhalten getrennte Bindungen. - Eine IIFE erzeugt einen Funktionsgültigkeitsbereich und führt die Funktion sofort aus.
- Erreichbare Closures halten die eingefangenen Daten erreichbar, die sie benötigen.
5Übergib Funktionen an andere Funktionen
Durch die Übergabe einer Funktion kann der aufrufende Code einen Teil des Verhaltens einer anderen Funktion bestimmen. Du wirst untersuchen, wie empfangende Funktionen Callbacks aufrufen, welche Argumente sie übergeben und wie sie das Ergebnis verwenden. Bekannte Arraymethoden werden dann zu Beispielen für wiederverwendbare Muster mit Funktionen höherer Ordnung. Schließlich werden zurückgegebene Funktionen Aufrufe umhüllen, Ausgaben mit Eingaben verbinden oder ausgewählte Argumente für die spätere Verwendung bereithalten und dabei Funktionswerte mit dem Zugriff über Closures verbinden.
5.1 Übergib einer Funktion einen Callback
Ein Callback ist eine Funktion, die als Argument übergeben wird, damit eine andere Funktion sie aufruft. So kann die empfangende Funktion die Gesamtaufgabe bearbeiten, während der aufrufende Code eine bestimmte Aktion oder Prüfung liefert.
Übergib eine Aktion an eine Schleife
function repeat(times, action) {
for (let i = 0; i < times; i++) {
action(i);
}
}
repeat(3, (i) => console.log(i));
repeat enthält die Schleife und wählt die Werte 0, 1 und 2. Die Pfeilfunktion bestimmt, was mit jedem Wert geschieht: Er wird ausgegeben. Jedes action(i) ruft die übergebene Funktion mit der Nummer des jeweiligen Schleifendurchlaufs auf.
Du kannst eine vorhandene Funktion übergeben oder eine direkt an Ort und Stelle schreiben. repeat(2, sayHi) übergibt die benannte Funktion. repeat(2, (i) => console.log("Round " + (i + 1))) gibt „Round 1“ und „Round 2“ aus. Ein Callback darf Argumente ignorieren, die er nicht benötigt.
Übergib den Wert und rufe die Funktion nicht vorzeitig auf
repeat(3, sayHi()) wertet sayHi() beim Vorbereiten der Argumente aus. Wenn sayHi nur etwas ausgibt, ist sein Rückgabewert undefined, sodass repeat diesen Wert als action erhält. Das spätere action(i) schlägt mit einem TypeError fehl, weil undefined nicht aufrufbar ist.
Verwende repeat(3, sayHi), um die Funktion zu übergeben. Wenn der spätere Aufruf ausgewählte Argumente benötigt, übergib einen Wrapper wie () => sayHi(), damit der Aufruf innerhalb des Callback-Rumpfs stattfindet. Das Erzeugen und das Aufrufen einer Funktion sind getrennte Schritte.
Prüfe, welche Argumente die empfangende Funktion liefert
Array-Callbacks erhalten oft mehr als ein Argument: Element, Index und das gesamte Array. Die Übergabe einer vorhandenen Funktion ist nur dann sicher, wenn diese Eingaben zur Bedeutung ihrer Parameter passen.
["1", "2", "3"].map(parseInt);
Dies gibt [1, NaN, NaN] zurück. parseInt akzeptiert ein zweites Argument für die Zahlenbasis, sodass der Arrayindex sein Verhalten ändert. Verwende ["1", "2", "3"].map((s) => parseInt(s, 10)), um die Basis 10 ausdrücklich zu wählen, oder .map(Number), um diese Zeichenketten umzuwandeln.
Gib eine Antwort an die empfangende Funktion zurück
function countIf(arr, test) {
let n = 0;
for (const x of arr) {
if (test(x)) {
n++;
}
}
return n;
}
countIf([3, 8, 12, 5], (x) => x > 4) gibt 3 zurück. Der Callback beantwortet für jedes Element eine Frage; countIf nutzt jede Antwort, um zu entscheiden, ob erhöht wird. Vergleiche repeat, dessen Schleife den Rückgabewert des Callbacks ignoriert. Der Code oder die Dokumentation der empfangenden Funktion nennt dir sowohl die Argumente als auch die Rolle des Ergebnisses.
Callbacks können sofort oder später ausgeführt werden. repeat und Arraymethoden rufen sie synchron auf, bevor sie zurückkehren. setTimeout(sayHi, 2000) plant einen Callback für später ein, während der nachfolgende Code sofort weiterläuft. Die Bezeichnung Callback beschreibt, wie eine Funktion übergeben wird, nicht wann sie ausgeführt werden muss.
Wichtige Erkenntnisse
- Ein Callback ist eine Funktion, die zum Aufruf durch eine andere Funktion übergeben wird.
- Die empfangende Funktion bestimmt die Argumente des Callbacks und ob sein Ergebnis verwendet wird.
- Zu früh gesetzte Aufrufklammern können ein Ergebnis statt einer Funktion übergeben.
- Argumente von Array-Callbacks können das Verhalten einer vorhandenen Funktion ändern.
- Callbacks können synchron oder verzögert ausgeführt werden.
5.2 Nutze und schreibe Funktionen höherer Ordnung
Eine Funktion höherer Ordnung nimmt eine Funktion entgegen, gibt eine Funktion zurück oder tut beides. Der Funktionswert liefert Verhalten, während die Funktion höherer Ordnung ein wiederverwendbares Muster verwaltet.
Schreibe das Muster einmal
function myMap(arr, transform) {
const result = [];
for (const item of arr) {
result.push(transform(item));
}
return result;
}
myMap([1, 2, 3], (n) => n * n) gibt [1, 4, 9] zurück. Die Schleife und das Erstellen des Ausgabearrays bleiben gleich; der Callback bestimmt, wie sich jeder Eintrag ändert. Ein entsprechender Filter fügt ein Element nur hinzu, wenn test(item) einen Truthy-Wert ergibt. Mit [4, 7, 10, 3] und (n) => n % 2 === 0 behält dieses Muster [4, 10].
Wähle den benötigten Vertrag für den Callback
| Methode | Aufgabe des Callbacks | Ergebnis der Methode |
|---|---|---|
map | Jeden transformierten Wert zurückgeben | Ein neues Array gleicher Länge |
filter | Für zu behaltende Elemente einen Truthy-Wert zurückgeben | Ein neues Array ausgewählter Elemente |
find | Auf ein passendes Element prüfen | Erster Treffer oder undefined |
forEach | Für jedes Element eine Aktion ausführen | undefined |
reduce | Den nächsten Akkumulator zurückgeben | Der endgültige Akkumulator |
map, filter und find verändern das Eingabearray selbst nicht, aber Callbacks können es dennoch verändern. Dass eine Methode ein neues Array zurückgibt, macht nicht jeden übergebenen Callback rein.
Führe ein Ergebnis durch eine Reduktion
[5, 10, 15].reduce((total, n) => total + n, 0);
Der anfängliche Akkumulator ist 0. Der Callback gibt für das erste Element 5, für das zweite 15 und für das dritte 30 zurück. Jeder Rückgabewert wird zum total des nächsten Aufrufs. Nach dem letzten Element gibt die Methode 30 zurück. Bei einem leeren Array ohne anfänglichen Akkumulator löst reduce einen TypeError aus; ein ausdrücklicher Anfangswert legt auch das nutzbare Ergebnis für eine leere Eingabe fest.
Da Methoden Arrays zurückgeben, lassen sich Aufrufe verketten. [3, 8, 12, 5].filter((n) => n > 4).map((n) => n * 2) behält zuerst [8, 12, 5] und transformiert es dann zu [16, 24, 10]. Lies die Kette in Ausführungsreihenfolge von links nach rechts.
Gib eine numerische Sortierregel an
Ohne Vergleichsfunktion vergleicht sort Einträge als Zeichenketten. [10, 9, 1].sort() ergibt daher [1, 10, 9]. Verwende für eine aufsteigende numerische Reihenfolge .sort((a, b) => a - b). Ein negativer Rückgabewert setzt a an die erste Stelle, ein positiver b, und bei null gelten die beiden für die Reihenfolge als gleichwertig. Anders als map und filter ordnet sort sein Eingabearray um.
Prüfe die Rückgabewerte
[1, 2, 3].map((n) => { n * 2; }) ergibt [undefined, undefined, undefined], weil der Block keine Rückgabe hat. Auch der Versuch, mit forEach durch Zuweisung ein neues Ergebnis zu erstellen, schlägt fehl, wenn du erwartest, dass die Methode selbst ein Array zurückgibt. Wähle map für Transformationen und forEach für Aktionen, deren gesammelte Ausgaben nicht benötigt werden.
Eine Methode höherer Ordnung drückt ein bekanntes Muster klar aus. Eine einfache Schleife bleibt nützlich, wenn die Arbeit break benötigt oder nicht zum Vertrag der Methode passt.
Wichtige Erkenntnisse
- Funktionen höherer Ordnung nehmen Funktionen entgegen, geben Funktionen zurück oder tun beides.
map,filterundfindverwenden Callback-Ergebnisse auf unterschiedliche Weise.forEachgibtundefinedzurück;reducegibt den endgültigen Akkumulator zurück.- Ein Reduktionscallback muss den nächsten Akkumulator zurückgeben.
- Numerisches Sortieren benötigt eine Vergleichsfunktion und verändert das ursprüngliche Array.
- Eine Methode, die ein neues Array zurückgibt, kann dennoch Callbacks mit Seiteneffekten ausführen.
5.3 Erstelle neue Funktionen aus vorhandenen Funktionen
Eine Funktion kann eine neue Funktion zurückgeben, die sich eine vorhandene merkt. Wrapper, Funktionskomposition und partielle Anwendung nutzen dieses Muster, um Verhalten anzupassen, ohne den Rumpf der ursprünglichen Funktion zu kopieren.
Umhülle einen Aufruf und erhalte sein Ergebnis
function logged(fn) {
return (...args) => {
console.log("Calling with", args);
const result = fn(...args);
console.log("Result", result);
return result;
};
}
const add = (a, b) => a + b;
logged(add) erzeugt eine Funktion, die add als fn behält. Der Aufruf logged(add)(2, 3) sammelt die Argumente, leitet sie an add weiter, gibt den Rückgabewert aus und liefert 5 zurück. Rest sammelt die Eingaben des Wrappers; Spread leitet sie weiter. Die abschließende Rückgabe hält die Ausgabe für spätere Berechnungen verfügbar.
logged(add(2, 3)) übergibt stattdessen die Zahl 5. Wird dieser Wrapper später aufgerufen, versucht er, 5 aufzurufen, und löst einen TypeError aus. Es gibt zwei Schritte: Konfiguriere den Wrapper mit einer Funktion und rufe dann die zurückgegebene Funktion mit Eingaben auf.
Behalte Zustand für eine Operation
function once(fn) {
let done = false;
let result;
return (...args) => {
if (!done) {
done = true;
result = fn(...args);
}
return result;
};
}
Bei einer Operation, die normal zurückkehrt, führt der erste Aufruf fn aus und speichert das Ergebnis. Spätere Aufrufe geben diesen gespeicherten Wert zurück, ohne fn erneut auszuführen, selbst wenn ihre Argumente verschieden sind. Der boolesche Wert hält fest, ob die Operation ausgeführt wurde; den Wahrheitswert des Ergebnisses zu prüfen, wäre falsch, wenn ein zulässiges Ergebnis 0 oder false ist. Jeder Aufruf von once erzeugt ein eigenes Flag und ein eigenes gespeichertes Ergebnis.
Übergib ein Ergebnis an eine andere Funktion
const compose = (f, g) => (x) => f(g(x));
const addOne = (n) => n + 1;
const square = (n) => n * n;
compose(square, addOne)(3) führt zuerst addOne(3) aus und quadriert dann 4, um 16 zurückzugeben. compose(addOne, square)(3) quadriert zuerst 3 und addiert dann 1; das Ergebnis ist 10. Die Funktion, die der Eingabe am nächsten steht, wird zuerst ausgeführt, sodass die Reihenfolge der Argumente von compose wichtig ist.
Lege einige Argumente im Voraus fest
function partial(fn, ...fixed) {
return (...rest) => fn(...fixed, ...rest);
}
const greetWith = (greeting, name) => greeting + ", " + name;
const hello = partial(greetWith, "Hello");
hello("Ana") ruft greetWith("Hello", "Ana") auf und gibt „Hello, Ana“ zurück. Diese Hilfsfunktion für partielle Anwendung setzt feste Argumente an den Anfang und spätere Argumente dahinter; eine Änderung dieser Reihenfolge ändert den zugrunde liegenden Aufruf.
Wichtige Erkenntnisse
- Ein Wrapper behält eine Funktion und ergänzt deren Aufruf um ein Verhalten.
- Rest und Spread ermöglichen einem Wrapper, einzelne Argumente weiterzuleiten.
- Die Rückgabe des Ergebnisses der umhüllten Funktion hält es für den aufrufenden Code nutzbar.
- Ein Once-Wrapper behält sowohl ein Flag als auch das erste Ergebnis.
compose(f, g)wendetgvorfan.- Partielle Anwendung legt ausgewählte Argumente vor späteren Aufrufen fest.
Funktionen und Closures in JavaScript: Beispiele
1Erstelle, speichere und rufe eine Funktion auf
11 Schritte
- 1EinführungTrenne das Rezept vom Aufruf
Eine Funktion speichert Anweisungen, sodass mehrere Aufrufe sie wiederverwenden können. Ihre Definition beschreibt eine Aufgabe; ein Aufruf führt diese Aufgabe mit bestimmten Eingaben aus.
Verfolge eine Begrüßung durch drei Formen: eine Deklaration, einen in einer Variablen gespeicherten Ausdruck und eine Pfeilfunktion. Achte bei den Änderungen der Syntax auf zwei Einzelheiten: wann die Funktion verfügbar wird und ob ihr Rumpf einen Wert zurückgibt.
- 2BeispielDefiniere eine Begrüßung
function greet(name) { console.log("Hello, " + name + "!"); }Das Schlüsselwort, der Name, die Parameterliste und der Rumpf bilden eine Deklaration. Bisher wurde nichts ausgegeben: Die Definition speichert die Anweisungen.
nameist ein Parameter, dessen Wert von einem Aufruf stammt. Der Rumpf lässt sich wiederverwenden, weil er beschreibt, wie die Begrüßung aufgebaut wird, ohne den Namen einer Person im Voraus festzulegen. - 3BeispielFühre die gespeicherten Anweisungen aus
greet("Amira"); greet("Li");Die Aufrufe geben „Hello, Amira!“ und „Hello, Li!“ in getrennten Zeilen aus. Jeder beginnt denselben Rumpf erneut mit seiner eigenen Eingabe.
Der Ausdruck
greetallein ist der Funktionswert. Die Klammern ingreet("Li")bewirken die Ausführung. Auch eine Funktion ohne Eingaben braucht Aufrufklammern, wie insayHi(). - 4HerausforderungSage das Ergebnis des frühen Aufrufs voraus
Was wird ausgegeben, wenn dieses Skript läuft?
show(); function show() { console.log("Ready"); }---reveal---
Es gibt einmal „Ready“ aus. Die Deklaration unterliegt innerhalb ihres Gültigkeitsbereichs dem Hoisting, sodass die Funktion in der ersten Zeile verfügbar ist. Hoisting führt den Rumpf nicht von selbst aus: Das tut der ausdrückliche Aufruf
show(). Eine Zeile, die nurshow;enthält, würde die Funktion lesen, ohne etwas auszugeben. - 5ErklärungBehalte die Funktion als Wert
const square = function (n) { return n * n; }; const alias = square;Der Ausdruck erzeugt eine Funktion und
squarespeichert sie. Die zweite Zuweisung kopiert ihre Referenz inalias; sie berechnet kein Quadrat. Sowohlsquare(3)als auchalias(3)geben 9 zurück.Im Vergleich dazu ruft
const answer = square(3);die Funktion auf und speichert die zurückgegebene Zahl. - 6HerausforderungFinde die erste Fehlerstelle
Gibt dieses Skript 16 aus?
console.log(square(4)); const square = function (n) { return n * n; };---reveal---
Nein. Das Lesen von
squarevor seiner Initialisierung mitconstlöst einenReferenceErroraus. Die Zuweisung wurde noch nicht ausgeführt, sodass der Funktionswert des Ausdrucks nicht verfügbar ist. Verschiebe den Aufruf unter die Zuweisung oder verwende eine Funktionsdeklaration, wenn die Funktion in diesem Gültigkeitsbereich früher aufrufbar sein muss. - 7BeispielVerwende einen Ausdrucksrumpf
const square = (n) => n * n; const add = (a, b) => a + b;Der Ausdrucksrumpf einer Pfeilfunktion gibt seinen Ausdruck zurück, sodass
square(4)den Wert 16 undadd(2, 3)den Wert 5 zurückgibt.Bei einem einfachen Parameter dürfen die Klammern entfallen:
n => n * n. Leere Listen, mehrere Parameter sowie Standard- und Restparameter brauchen sie. Pfeilfunktionen sind Ausdrücke, sodass dieseconst-Variablen vor der Verwendung weiterhin initialisiert werden müssen. - 8HerausforderungBehebe ein fehlendes Ergebnis
Warum gibt
add(2, 3)den Wertundefinedzurück und welche Änderung führt dazu, dass 5 zurückgegeben wird?const add = (a, b) => { a + b; };---reveal---
Die geschweiften Klammern beginnen einen Block, sodass der Ausdruck ausgewertet, aber nicht zurückgegeben wird. Schreibe
(a, b) => { return a + b; }oder entferne die geschweiften Klammern und verwende(a, b) => a + b. Beide Korrekturen geben die Summe zurück. Ein bloßes Semikolon nach der Zuweisung ändert das Rückgabeverhalten des Rumpfs nicht. - 9TippGib einen Objektausdruck zurück
const makePoint = (x, y) => ({ x: x, y: y });Die runden Klammern machen das Objektliteral zu einem Ausdruck, der vom Ausdrucksrumpf zurückgegeben wird. Eine öffnende geschweifte Klammer ohne umgebende runde Klammern würde stattdessen einen Block beginnen.
Pfeilfunktionen haben kein eigenes
thisoderargumentsund können keine Konstruktoren sein. Die kurze Form eignet sich gut für einfache Berechnungen, aber diese Unterschiede sind wichtig, wenn andere Arten von Funktionen umgeschrieben werden. - 10HerausforderungVerfolge eine Funktion und ihren weiteren Namen
Was gibt
copy(5)zurück?const adjust = (n) => { return n + 2; }; const copy = adjust;---reveal---
Der Aufruf gibt 7 zurück. Der Block der Pfeilfunktion enthält eine ausdrückliche Rückgabe und
copyenthält dieselbe aufrufbare Funktion wieadjust. Die Zuweisung hat die Funktion nicht aufgerufen und kein numerisches Ergebnis gespeichert. Würdest duconst copy = adjust;durchconst copy = adjust(5);ersetzen, würde 7 gespeichert, was nicht aufrufbar ist. - 11ZusammenfassungLies die Operation in jeder Zeile
Eine Deklaration erzeugt eine benannte Aufgabe, die früh in ihrem Gültigkeitsbereich verfügbar ist. Ein Ausdruck erzeugt einen Funktionswert, wenn die Ausführung ihn erreicht. Der Ausdrucksrumpf einer Pfeilfunktion gibt automatisch zurück; ihr Blockrumpf braucht
return.Unterscheide beim Verfolgen von Code zwischen einer Funktionsdefinition, der Zuweisung einer Referenz und einem Aufruf. Das sind verschiedene Operationen, auch wenn sie denselben Namen verwenden.
2Verfolge Eingaben, Ausgaben und wartende Aufrufe
16 Schritte
Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.
- 1EinführungVerfolge, was in einen Aufruf hinein- und herausgeht
- 2BeispielOrdne Argumente nach ihrer Position zu
- 3BeispielUnterscheide Mutation und Neuzuweisung
- 4HerausforderungErhalte die ursprüngliche Eingabe
- 5ErklärungDer Standardwert gilt bei undefined
- 6BeispielSammle und entfalte anschließend
- 7HerausforderungVerwende einen Standardwert mit Rest
- 8BeispielGib die benötigte Zahl an den aufrufenden Code zurück
- 9BeispielBeende einen Ausführungszweig mit einer vorzeitigen Rückkehr
- 10HerausforderungWerte von innen nach außen aus
- 11BeispielBehalte den nicht abgeschlossenen Aufruf im Blick
- 12ErklärungGib der Rekursion einen Pfad zum Anhalten
- 13BeispielArbeite die wartenden Produkte rückwärts ab
- 14HerausforderungKorrigiere eine rekursive Abbruchbedingung
- 15VerbindungLies einen Fehler anhand des Stapels
- 16ZusammenfassungVerfolge einen Wert über jede Grenze
3Finde die Deklaration hinter einem Namen
10 Schritte
Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.
- 1EinführungFrag dich, wohin der Name gehört
- 2BeispielVergleiche Block- und Funktionsgrenzen
- 3BeispielNutze die Stelle der Definition
- 4HerausforderungVerfolge einen lokalen und einen äußeren Wert
- 5ErklärungHalte bei der nächstgelegenen Deklaration an
- 6KernaussageRegistriert bedeutet nicht initialisiert
- 7HerausforderungSage das Lesen eines verdeckten Namens voraus
- 8TippUnterscheide Neuzuweisung und Mutation
- 9HerausforderungVerbinde einen Callback mit dem Zeitpunkt der Suche
- 10ZusammenfassungBestimme vor dem Wert die Stelle
4Gib zurückgegebenen Funktionen ein eigenes Gedächtnis
11 Schritte
Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.
- 1EinführungBehalte den Zugriff nach einer Rückkehr
- 2BeispielErstelle einen Zähler, ohne ihn aufzurufen
- 3BeispielAktualisiere die erhaltene Variable
- 4HerausforderungVergleiche unabhängige Zähler
- 5KernaussageBehalte die Bindung, keine Momentaufnahme
- 6BeispielErstelle eine konfigurierte Berechnung
- 7BeispielHalte einen Nutzungszähler privat
- 8HerausforderungErkläre drei gleiche Ergebnisse
- 9VerbindungErkenne einen privaten Gültigkeitsbereich in älterem Code
- 10HerausforderungTeile eine konfigurierte Operation
- 11ZusammenfassungVerfolge, wie viele Umgebungen existieren
5Übergib Verhalten und erstelle angepasste Funktionen
15 Schritte
Speichere diese Einheit, um jede Interaktive Lektion Schritt für Schritt durchzugehen.
- 1EinführungLass eine Funktion das veränderliche Verhalten liefern
- 2BeispielRufe die übergebene Aktion auf
- 3HerausforderungVerwende ein Callback-Ergebnis
- 4TippUntersuche alle Callback-Argumente
- 5BeispielSchreibe ein Transformationsmuster
- 6ErklärungWähle die Form des Ergebnisses
- 7HerausforderungVerfolge eine Auswahl und eine Transformation
- 8KernaussageAchte bewusst auf numerische Reihenfolge
- 9BeispielUmhülle einen Aufruf und leite ihn weiter
- 10ErklärungMerke dir, ob ein Aufruf ausgeführt wurde
- 11BeispielSetze Funktionen von innen nach außen zusammen
- 12BeispielLege Eingaben vor dem späteren Aufruf fest
- 13HerausforderungÜbergib einen konfigurierten Callback
- 14HerausforderungBehebe ein verlorenes Wrapper-Ergebnis
- 15ZusammenfassungPrüfe beide Schritte bei Funktionen höherer Ordnung
Funktionen und Closures in JavaScript: Übungsaufgaben
Set 1: Lies Funktionen und verfolge ihre Werte10 Übungsfragen
Frage 1 von 10
function showLabel() { console.log("Ready"); }. Welche Anweisung ruft die Funktion auf?Antwort zeigenAntwort ausblenden
showLabel(); ruft die Funktion auf, sodass ihr Rumpf „Ready“ ausgibt. Das Lesen von showLabel ohne Klammern liefert nur den Funktionswert; auch die Zuweisung dieses Werts an einen anderen Namen führt den Rumpf nicht aus. Die Aufrufklammern sind auch ohne Argumente nötig.Frage 2 von 10
Was enthält copy nach diesem Code?
const triple = function (n) { return n * 3; };
const copy = triple;
Antwort zeigenAntwort ausblenden
triple und speichert dieselbe Referenz in copy. Auf der rechten Seite steht kein Aufruf, daher wird kein numerisches Ergebnis berechnet. Ein späteres copy(4) würde diese Funktion aufrufen und 12 zurückgeben; das Kopieren ihrer Referenz führt sie nicht aus.Frage 3 von 10
Was gibt adjust(8) zurück?
const adjust = (n) => { n - 3; };
Antwort zeigenAntwort ausblenden
return. Er wertet die Subtraktion aus, endet aber mit undefined. Das Ergebnis wäre 5 mit einem Ausdrucksrumpf, (n) => n - 3, oder mit einem ausdrücklichen return n - 3; innerhalb des Blocks.Frage 4 von 10
Was gibt difference(12, 5) zurück?
function difference(first, second) {
return first - second;
}
Antwort zeigenAntwort ausblenden
first auf 12 und das zweite second auf 5. Die Subtraktion in der Reihenfolge des Rumpfs ergibt 7. Das Ergebnis -7 entstünde durch Vertauschen der Argumentpositionen; Parameternamen ordnen die vom Aufruf gelieferten Werte nicht um.Frage 5 von 10
Was gibt readLevel(0) zurück?
function readLevel(level = 40) { return level; }
Antwort zeigenAntwort ausblenden
undefined, sodass es 0 bleibt. Ein Standardparameter ersetzt nicht jeden Falsy-Wert. Der ältere Ausdruck level || 40 würde 0 durch 40 ersetzen, aber dafür gilt eine andere Regel als für den Standardwert in der Definition.Frage 6 von 10
Welche Zahl wird ausgegeben und welchen Wert hat result?
function displayTotal(a, b) { console.log(a + b); }
const result = displayTotal(6, 9);
Antwort zeigenAntwort ausblenden
undefined speichert. Eine Zahl in der Konsole bedeutet nicht, dass der Aufruf diese Zahl zurückgegeben hat; dafür bräuchte der Rumpf return a + b;.Frage 7 von 10
Was geschieht beim Aufruf von getFlag()?
function getFlag() {
if (true) { let flag = "on"; }
return flag;
}
Antwort zeigenAntwort ausblenden
let-Deklaration gehört zum if-Block. Bei der Rückgabe außerhalb dieses Blocks existiert keine zugängliche Deklaration von flag, sodass das Lesen einen ReferenceError auslöst. Würde let durch var ersetzt, hätte die Variable Funktionsgültigkeitsbereich und die Funktion könnte „on“ zurückgeben.Frage 8 von 10
Welche Werte geben die beiden Aufrufe der Reihe nach zurück?
function makeStep() {
let value = 4;
return () => { value += 2; return value; };
}
const step = makeStep();
step();
step();
Antwort zeigenAntwort ausblenden
value-Bindung. Die zurückgegebene Funktion behält Zugriff darauf, sodass der erste Aufruf sie auf 6 und der zweite dieselbe Bindung auf 8 aktualisiert. Die Rückkehr aus der Fabrik setzt die eingefangene Variable vor späteren Aufrufen nicht jeweils zurück.Frage 9 von 10
Wie lautet die vollständige Reihenfolge der ausgegebenen Werte?
function deliver(action) { action(7); }
console.log("start");
deliver((n) => console.log(n));
console.log("end");
Antwort zeigenAntwort ausblenden
deliver ruft die übergebene Pfeilfunktion sofort mit 7 auf, bevor es zum umgebenden Skript zurückkehrt. Die Ausgabe lautet daher „start“, 7, dann „end“. Ein Callback wird nicht zwangsläufig verzögert ausgeführt; diese empfangende Funktion enthält einen gewöhnlichen direkten Aufruf und keine Einplanung.Frage 10 von 10
Was ist der endgültige Wert von result?
const values = [2, 7, 4, 9];
const result = values
.filter((n) => n > 3)
.map((n) => n - 1)
.reduce((total, n) => total + n, 5);
Antwort zeigenAntwort ausblenden
[7, 4, 9] und die Transformation macht daraus [6, 3, 8]. Die Reduktion ab dem Anfangswert 5 ergibt 11, dann 14 und dann 22. Das Ergebnis 17 lässt den angegebenen Anfangsakkumulator weg und summiert nur die transformierten Elemente, wodurch sich die Bedeutung des letzten Aufrufs ändert.Set 2: Wähle Eingaben und verfolge erhaltenen Zustand10 Übungsfragen
Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.
Frage 1 von 10
Was geschieht, wenn dieses Skript ausgeführt wird?
announce();
function announce() { console.log("Open"); }
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 2 von 10
value gleich ihrer Eingabe n ist?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 3 von 10
Was gibt der Aufruf zurück?
function combine(first, ...rest) {
return first + rest.length;
}
const values = [8, 2, 6];
combine(...values);
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 4 von 10
Was gibt guarded(0) zurück?
function guarded(n) {
if (n === 0) { return "empty"; }
return "filled";
}
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 5 von 10
Was gibt totalDown(3) zurück?
function totalDown(n) {
if (n === 0) { return 0; }
return n + totalDown(n - 1);
}
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 6 von 10
Was geschieht beim Aufruf von read()?
let label = "outer";
function read() {
return label;
let label = "inner";
}
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 7 von 10
Was gibt der letzte Aufruf zurück?
let word = "first";
const read = () => word;
word = "second";
function run() {
const word = "third";
return read();
}
run();
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 8 von 10
Welches Array erzeugt der letzte Ausdruck?
const readers = [];
for (let i = 1; i <= 3; i++) {
let value = i;
readers.push(() => value);
value += 10;
}
readers.map((read) => read());
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 9 von 10
Was geschieht, wenn die letzte Zeile ausgeführt wird?
function speak() { console.log("Hi"); }
function twice(action) { action(); action(); }
twice(speak());
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 10 von 10
Was ist das endgültige Ergebnis?
const compose = (f, g) => (x) => f(g(x));
const subtract = (n) => n - 2;
const triple = (n) => n * 3;
const first = compose(triple, subtract);
const second = compose(subtract, triple);
first(second(4));
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Set 3: Verbinde Aufrufe, Gültigkeitsbereiche und Callbacks10 Übungsfragen
Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.
Frage 1 von 10
Was geschieht, wenn dieses Skript ausgeführt wird?
const saved = build;
const build = function () { return 9; };
console.log(saved());
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 2 von 10
Welcher Wert wird out zugewiesen?
const describe = (n) => {
const doubled = n * 2;
return doubled + 1;
};
const out = describe(6);
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 3 von 10
Was sind items und answer nach diesem Code?
const items = [5];
function change(list) {
list.push(8);
list = [1];
return list;
}
const answer = change(items);
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 4 von 10
Was gibt countLeaves([0, [[], 2], [[3], 4]]) zurück?
function countLeaves(list) {
let count = 0;
for (const item of list) {
if (Array.isArray(item)) {
count += countLeaves(item);
} else {
count++;
}
}
return count;
}
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 5 von 10
Was gibt readValue() zurück?
function readValue() {
if (true) { var value = 14; }
return value;
}
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 6 von 10
Welche zwei Werte werden ausgegeben?
let count = 2;
function update() {
let count = 7;
count += 1;
return count;
}
console.log(update());
console.log(count);
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 7 von 10
Welche Werte geben die letzten drei Aufrufe zurück?
function makeCounter(start) {
let n = start;
return () => { n++; return n; };
}
const a = makeCounter(5);
const alias = a;
const b = makeCounter(5);
a();
alias();
b();
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 8 von 10
Was gibt scale(7) zurück?
const makeScale = (factor) => (n) => n * factor;
const scale = makeScale(4);
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 9 von 10
Was sind values und first danach?
const values = [12, 3, 20];
const first = values.sort((a, b) => a - b)[0];
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 10 von 10
Was geben die Aufrufe read(0) und read(9) der Reihe nach zurück?
function once(fn) {
let done = false;
let result;
return (...args) => {
if (!done) {
done = true;
result = fn(...args);
}
return result;
};
}
const read = once((n) => n * 2);
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Set 4: Untersuche das Verhalten von Funktionen in kleinen Programmen10 Übungsfragen
Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.
Frage 1 von 10
function printLine() { console.log("---"); } und führt dann printline(); aus. Was geschieht?Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 2 von 10
Was gibt der letzte Aufruf zurück?
const climb = function step(n) {
return n === 0 ? 0 : 1 + step(n - 1);
};
const saved = climb;
saved(2);
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 3 von 10
Was sind data und result am Ende?
const data = [2, 5];
function extend(list, item) {
const next = list.concat(item);
list.push(9);
return next;
}
const result = extend(data, 7);
result.push(1);
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 4 von 10
Was gibt der letzte Aufruf zurück?
function total(base = 4, ...extras) {
return extras.reduce((sum, n) => sum + n, base);
}
const values = [undefined, 3, 0, 8];
total(...values);
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 5 von 10
Welchen Wert liefert dieser Aufruf?
function read() {
return;
}
read();
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 6 von 10
Die Eingabe n ist eine nicht negative Ganzzahl. Welcher Ersatz für die rekursive Rückgabe lässt die Funktion sowohl bei ungeraden als auch bei geraden Eingaben korrekt bis 0 herunterzählen?
function countDown(n) {
if (n === 0) { return 0; }
// recursive return goes here
}
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 7 von 10
Was gibt der letzte Aufruf zurück?
const mode = "shared";
function readMode() { return mode; }
function run() {
const mode = "local";
return readMode();
}
run();
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 8 von 10
Welche Werte geben jobs[0]() und jobs[1]() nach der Schleife zurück?
const jobs = [];
for (var i = 0; i < 2; i++) {
const offset = i * 10;
jobs.push(() => offset + i);
}
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 9 von 10
Welches Ergebnis liefert dieser Ausdruck?
["6", "8", "10"].map((text) => parseInt(text, 10));
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 10 von 10
Welche Werte von out und seen werden ausgegeben?
let seen = 0;
const out = [3, 5].forEach((n) => {
seen += n;
return n * 2;
});
console.log(out, seen);
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Set 5: Kombiniere Closures und Funktionen höherer Ordnung10 Übungsfragen
Speichere diese Einheit, um jede Antwort zu sehen und jedes Set zu üben.
Frage 1 von 10
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 2 von 10
Zu welchem Wert wird add("6", 4) * 2 ausgewertet?
function add(a, b) { return a + b; }
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 3 von 10
Zu welchem Wert wird der letzte Ausdruck ausgewertet?
function choose(n) {
if (n < 0) { return 0; }
return n + 2;
}
choose(choose(-4));
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 4 von 10
Was geschieht beim Aufruf von build()?
let amount = 6;
function build() {
const read = () => amount;
const result = read();
let amount = 9;
return result;
}
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 5 von 10
Welche Werte geben change(3), read() und otherRead() zurück?
function makePair() {
let n = 1;
return [
(step) => { n += step; return n; },
() => n
];
}
const [change, read] = makePair();
const [, otherRead] = makePair();
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 6 von 10
Was gibt der letzte Ausdruck zurück?
function makeLimit(max) {
let used = 0;
return () => {
if (used >= max) { return false; }
used++;
return true;
};
}
const allow = makeLimit(2);
[allow(), allow(), allow()];
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 7 von 10
Was sind result und calls nach diesem Code?
let calls = 0;
function choose(values, test) {
for (const value of values) {
calls++;
if (test(value)) { return value; }
}
return null;
}
const result = choose([3, 8, 10, 5], (n) => n > 6 && n % 2 === 0);
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 8 von 10
Was sind items und out danach?
const items = [2, 4, 6];
const out = items.map((n, index, array) => {
array[index] = n + 1;
return n * 2;
});
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 9 von 10
Was gibt doubleSaved(9) nach dem gezeigten früheren Aufruf zurück?
function once(fn) {
let done = false;
let saved;
return (...args) => {
if (!done) { done = true; saved = fn(...args); }
return saved;
};
}
const compose = (f, g) => (x) => f(g(x));
const saved = once((n) => n + 3);
const doubleSaved = compose((n) => n * 2, saved);
saved(4);
doubleSaved(9);
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Frage 10 von 10
Wie lautet das zurückgegebene Array?
const partial = (fn, ...fixed) => (...later) => fn(...fixed, ...later);
const offset = (base, n) => base + n;
const addFive = partial(offset, 5);
const compose = (f, g) => (x) => f(g(x));
const transform = compose((n) => n * n, addFive);
[1, 3].map(transform);
Antwort zeigenAntwort ausblenden
Speichere diese Einheit, um diese Antwort zu sehen.
Hängst du bei deiner eigenen Aufgabe fest? Hausaufgabenhilfe
Schlüsselbegriffe
A
Akkumulator
[5, 10, 15] auf 5, 15 und 30.Anonyme Funktion
function (n) { return n * n; } hat in seiner geschriebenen Syntax keinen internen Funktionsnamen.Argument
area(4, 2.5) sind die Argumente 4 und 2,5, unabhängig davon, wie die Parameter benannt wurden.arguments-Objekt
arguments[0] lesen, aber arguments.map nicht als gewöhnliche Arraymethode aufrufen.Array-Destrukturierung
const [low, high] = minMax(values); entpackt die beiden Einträge des zurückgegebenen Arrays.Aufrufstapel
sumOfSquares auf square(3) wartet, liegt ein Rahmen für den square-Aufruf über dem wartenden Aufruf.Ausdrucksrumpf
(a, b) => a + b gibt die Summe der beiden übergebenen Argumente direkt zurück.B
Basisfall
n <= 1 die Aufrufe bei 0 oder 1 an.Benannter Funktionsausdruck
const factorial = function fact(n) { /* body */ }; ist die äußere Variable factorial und der interne Name fact.Bindung
Blockgültigkeitsbereich
if deklariertes let message kann von einer Anweisung nach dem Ende dieses Blocks nicht gelesen werden.Blockrumpf
(n) => { n * 2; } berechnet ein Produkt, gibt aber undefined zurück, weil sie keine return-Anweisung hat.C
Callback
countIf-Hilfsfunktion ruft ihren Prüfcallback für jedes Element auf und zählt diejenigen, deren Prüfergebnisse Truthy-Werte sind.camelCase
calculateTotal beschreibt eine Aktion und trennt seine beiden Wörter ohne Leerzeichen oder Unterstriche.Closure
count weiter erhöhen, nachdem die Fabrik, die sie erzeugt hat, beendet ist.E
Eingefangene Variable
greeting von „Hi“ zu „Hello“ geändert, ändert sich der Wert, den ein späterer Aufruf einer Funktion zurückgibt, die greeting liest.F
Falsy-Wert
level || 50 ersetzt 0, während ein Parameterstandardwert diesen übergebenen Wert erhält.Funktion
printHeading("Report") und printHeading("Totals") auf, um dieselbe Routine für Überschriften wiederzuverwenden.Funktion höherer Ordnung
Funktionsaufruf
sayHi() führt den Rumpf aus, während eine Zeile, die nur sayHi enthält, den Funktionswert liest.Funktionsausdruck
const square = function (n) { return n * n; }; liefert der Ausdruck den Wert, der in square gespeichert wird.Funktionsdeklaration
greet("Li") kann im selben Gültigkeitsbereich oberhalb der geschriebenen Deklaration von greet stehen.Funktionsfabrik
makeMultiplier(3) gibt eine Funktion zurück, die sich 3 merkt und später eine Zahl zum Multiplizieren entgegennimmt.Funktionsgültigkeitsbereich
if-Block zugewiesenes var result kann später aus dem umschließenden Funktionsrumpf zurückgegeben werden.Funktionskomposition
f(g(x)) kann die Änderung der Reihenfolge zu g(f(x)) das Ergebnis ändern, selbst wenn beide Funktionen Zahlen entgegennehmen.Funktionsreferenz
const alias = square; ruft alias(4) die Funktion auf, die auch über square erreichbar ist.Funktionsrumpf
printHeading drei Ausgabeanweisungen, werden alle drei bei jedem Aufruf dieser Funktion erneut ausgeführt.G
Gemeinsam genutzter Zustand
balance zugreifen.Globaler Gültigkeitsbereich
count auf oberster Ebene eines Skripts kann zu gemeinsam genutztem Zustand werden, wenn mehrere Funktionen es lesen oder aktualisieren.Gültigkeitsbereichskette
amount, bevor sie eine gleichnamige Variable in einem äußeren Gültigkeitsbereich berücksichtigt.H
Hoisting
var vor seiner Zuweisung ergibt undefined; ein früher Aufruf einer Funktionsdeklaration kann ausgeführt werden.I
IIFE
(function () { var hidden = 1; })(); rufen die neu erzeugte Funktion auf.Inline-Funktion
repeat(3, (i) => console.log(i)) liefert die Aktion ohne eigene benannte Deklaration.Iterationsbindung
let i-Schleifendurchläufen können nach dem Ende der Schleife unterschiedliche Werte zurückgeben.L
Lexikalischer Gültigkeitsbereich
Lokale Variable
total verwenden, ohne dass ihre Additionen einander beeinflussen.M
Methodenkette
Mutation
arr.push(3) aufruft, ändert dasselbe Array, das der aufrufende Code als Argument übergeben hat.N
Neuzuweisung
arr = [] den Parameter auf ein anderes Array verweisen, ohne die Arrayreferenz des aufrufenden Codes zu ersetzen.O
Objektliteral
(n) => ({ value: n }) gibt ein Objekt zurück, statt ihre geschweiften Klammern als Anweisungsblock zu behandeln.Once-Wrapper
P
Parameter
width und height sind Parameter in function area(width, height) { return width * height; }.Partielle Anwendung
Pfeilfunktion
(n) => n * 2 liefert einen kurzen Transformationscallback für eine Arraymethode wie map.Prädikat
(n) => n > 4 wählt aus, welche Zahlen ein Filter behält, ohne deren Werte selbst zu ändern.Privater Zustand
used direkt unzugänglich.R
Reine Funktion
n * 2 zurückgibt, ist rein; die Ausgabe des Produkts würde einen Seiteneffekt einführen.Rekursion
Rekursiver Fall
n * factorial(n - 1) wartet auf die kleinere Fakultät, bevor er mit dem n dieses Aufrufs multipliziert.Restparameter
function log(label, ...values) { /* body */ } steht das erste Argument getrennt vom Restarray.Rückgabewert
double(5) den Wert 10 zurück, kann der Ausdruck double(5) + 1 diesen Wert sofort verwenden, um 11 zu erzeugen.S
Seiteneffekt
Spread-Syntax
Math.max(...[3, 7, 2]) übergibt drei Zahlen, statt ein Array an Math.max zu übergeben.Stacktrace
Standardparameter
level = 50 erhält eine ausdrücklich übergebene 0, liefert aber 50, wenn das Argument fehlt.Stapelrahmen
n behalten, weil sie getrennte Rahmen haben.Strikter Modus
"use strict";, löst eine nicht deklarierte Zuweisung count = 5; einen ReferenceError aus.Synchroner Callback
T
Transformationscallback
(n) => n * n verwandelt die Einträge von [1, 2, 3] durch eine Transformationsoperation in Quadrate.V
Verdeckung
count verbirgt innerhalb dieser Funktion ein äußeres count, ohne die äußere Bindung zu ändern.Vergleichsfunktion
(a, b) => a - b sortiert Zahlen aufsteigend, während sort das Eingabearray umordnet.Verzögerter Callback
sayHi an setTimeout lässt nachfolgende Anweisungen laufen, bevor die eingeplante Begrüßung erscheint.Vorzeitige Rückkehr
null zurückgeben, bevor die Ausführung die Divisionsanweisung erreicht.W
Wächterklausel
if (b === 0) { return null; } sichert die in safeDivide danach stehende Division ab.Wrapper
Z
Zeitliche Totzone
Über diese Einheit
Erstelle deine eigenen Lernmaterialien
Mach aus deinen Notizen, Folien und Dokumenten Lernleitfäden, Übungsfragen, Karteikarten und 6 weitere Tools.