Zum Inhalt springen
aviral gupta

// B4.4 · ca. 30 Min. · Einstieg

Pfeilfunktionen und Gültigkeitsbereiche

Nach dieser Lektion schreiben Sie Pfeilfunktionen, wissen, wo ein let oder const gilt, und können erklären, was sich eine Closure merkt.

Lektion 4 von 5 in B4 Funktionen

Danach können Sie

  • Pfeilfunktionen mit kurzem Rumpf oder Blockrumpf schreiben, ein Objekt in Klammern zurückgeben und Pfeile als Callbacks übergeben
  • Sagen, wo ein let oder const gilt: Block-, Funktions- und Modul-Scope, Verschattung, Scope-Kette
  • Eine Closure erklären: eine Funktion, die sich die Variablen ihres Entstehungsorts merkt
  1. Aufwärmen · Aufgabe 1 von 7

    Zum Aufwärmen: triple ist eine Pfeilfunktion. Was gibt dieser Code aus?

    const triple = (n) => n * 3;
    console.log(triple(4));
  2. Vorhersagen · Aufgabe 2 von 7

    Sagen Sie voraus, bevor Sie weiterlesen: Der Pfeil soll ein Objekt zurückgeben. Was gibt dieser Code aus?

    const makeUser = (name) => { name: name };
    console.log(makeUser("Ada"));
  3. Üben · Aufgabe 3 von 7

    Reparieren Sie den Pfeil, sodass er ein Objekt mit dem Schlüssel name zurückgibt. Ergänzen Sie seinen Rumpf.

    const makeUser = (name) => ____;
    console.log(makeUser("Ada"));
    const makeUser = (name) => ;
  4. Üben · Aufgabe 4 von 7

    Es gibt zwei Konstanten namens city. Was gibt dieser Code aus?

    const city = "Berlin";
    function show() {
      const city = "Hamburg";
      console.log(city);
    }
    show();
    console.log(city);
  5. Üben · Aufgabe 5 von 7

    Ordnen Sie jedem Ort, an dem ein const deklariert wird, zu, wo es verwendet werden kann.

  6. Denksport · Aufgabe 6 von 7

    Knobelaufgabe. Zwei Zähler stammen aus derselben Funktion. Was gibt dieser Code aus?

    function makeCounter() {
      let count = 0;
      return () => {
        count += 1;
        return count;
      };
    }
    const a = makeCounter();
    const b = makeCounter();
    a();
    a();
    console.log(a(), b());
  7. Anwenden · Aufgabe 7 von 7

    Kleine Aufgabe. Schreiben Sie makeGreeter(greeting), das eine Pfeilfunktion zurückgibt, die einen Namen erhält und einen Gruß wie Hello, Ada! zurückgibt. Erzeugen Sie zwei Grußfunktionen mit verschiedenen Wörtern, rufen Sie jede auf und am Ende die erste noch einmal: Sie verwendet weiterhin ihr eigenes Wort. Versuchen Sie dann, greeting unterhalb der Funktion auszugeben, und lesen Sie die Fehlermeldung.

    Prüfen Sie Ihr Ergebnis anhand dieser Liste

Selbst programmieren

Lesen Sie das ausgearbeitete Beispiel und lösen Sie dann die Übungen. Ihr Code läuft in Ihrem Browser oder auf Ihrem Computer und wird nie hochgeladen.

Ausgearbeitetes Beispiel

Ein Rundgang durch Pfeile, Scopes und eine Closure

Das Programm schreibt drei Pfeilfunktionen: eine mit kurzem Rumpf, eine mit Blockrumpf und eine, die ein Objekt in runden Klammern zurückgibt. Es übergibt einen Pfeil direkt als Callback an printEach. Dann zeigen drei Konstanten namens place den Modul-, Funktions- und Block-Scope, und makeGreeter gibt Pfeile zurück, die sich ihren Gruß merken. Führen Sie es aus, entfernen Sie dann die runden Klammern um das Objekt in makeItem und führen Sie es erneut aus.

main.js

// Arrow functions, three scopes and a first closure.
const double = (n) => n * 2;
const describe = (item, price) => {
  const label = price > 10 ? "expensive" : "cheap";
  return `${item} is ${label}`;
};
const makeItem = (name, price) => ({name: name, price: price});

console.log(double(21));
console.log(describe("tea", 4));
console.log(makeItem("tea", 4));

function printEach(values, change) {
  for (const value of values) {
    console.log(value, "->", change(value));
  }
}
printEach([1, 2, 3], (n) => n * 10);

const place = "module";
function showScope() {
  const place = "function";
  if (place === "function") {
    const place = "block";
    console.log("in the block:", place);
  }
  console.log("in the function:", place);
}
showScope();
console.log("at the top:", place);

function makeGreeter(greeting) {
  return (name) => `${greeting}, ${name}!`;
}
const hello = makeGreeter("Hello");
const hi = makeGreeter("Hi");
console.log(hello("Ada"));
console.log(hi("Linus"));

Ausführen mit

node main.js

Ausgabe

42
tea is cheap
{ name: 'tea', price: 4 }
1 -> 10
2 -> 20
3 -> 30
in the block: block
in the function: function
at the top: module
Hello, Ada!
Hi, Linus!
  • double hat einen kurzen Rumpf und gibt n * 2 ohne das Wort return zurück; describe hat geschweifte Klammern und braucht return.
  • makeItem gibt nur wegen der runden Klammern um die geschweiften ein Objekt zurück.
  • (n) => n * 10 steht genau dort, wo printEach eine Funktion braucht: ein Callback.
  • Jedes place ist eine andere Konstante; die innerste gilt dort, wo sie deklariert ist, die äußeren bleiben unberührt.
  • hello und hi stammen aus derselben Funktion, merken sich aber verschiedene Grüße.
Ändern und ausführen

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.

Übungen

Übung 1 von 2

Pfeilfunktionen, die etwas zurückgeben

Drei Pfeilfunktionen im Startcode geben das Falsche zurück. square(n) soll n mal n zurückgeben. wrap(value) soll ein Objekt mit einem Schlüssel value zurückgeben, sodass wrap(5) { value: 5 } liefert. isBetween(n, low, high) soll true zurückgeben, wenn n zwischen low und high liegt, beide eingeschlossen. Lassen Sie export vor jeder Konstante stehen, damit die Tests sie importieren können.

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.

Hinweise
  1. Hinweis 1

    Führen Sie die Tests aus: square und wrap geben undefined zurück. Was beginnen geschweifte Klammern direkt nach =>?

  2. Hinweis 2

    Ein Blockrumpf braucht return. Oder lassen Sie die geschweiften Klammern weg: (n) => n * n gibt den Ausdruck zurück.

  3. Hinweis 3

    Setzen Sie bei wrap das Objekt in runde Klammern: (value) => ({value: value}). Verbinden Sie bei isBetween zwei Vergleiche mit &&.

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

// Return n times n.
export const square = (n) => n * n;

// Return an object with one key, value, holding the argument.
export const wrap = (value) => ({value: value});

// Return true when n is from low to high, both included.
export const isBetween = (n, low, high) => n >= low && n <= high;
Auf dem eigenen Computer ausführen

Installieren Sie ECMAScript 2026 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.js

// Return n times n.
export const square = (n) => {
  n * n;
};

// Return an object with one key, value, holding the argument.
export const wrap = (value) => { value: value };

// Return true when n is from low to high, both included.
export const isBetween = (n, low, high) => false;

main.test.js

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {square, wrap, isBetween} from './main.js';

test('square(4) gibt 16 zurück', () => {
  assert.equal(square(4), 16, `square(4) hat ${square(4)} zurückgegeben, erwartet 16`);
});

test('square funktioniert mit negativen Zahlen', () => {
  assert.equal(square(-3), 9, `square(-3) hat ${square(-3)} zurückgegeben, erwartet 9`);
});

test('wrap(5) gibt ein Objekt mit dem Schlüssel value zurück', () => {
  assert.deepEqual(wrap(5), {value: 5}, `wrap(5) hat ${JSON.stringify(wrap(5))} zurückgegeben, erwartet {"value":5}`);
});

test('isBetween schließt beide Enden ein', () => {
  assert.equal(isBetween(1, 1, 10), true, `isBetween(1, 1, 10) hat ${isBetween(1, 1, 10)} zurückgegeben, erwartet true`);
  assert.equal(isBetween(10, 1, 10), true, `isBetween(10, 1, 10) hat ${isBetween(10, 1, 10)} zurückgegeben, erwartet true`);
});

test('isBetween ist außerhalb des Bereichs false', () => {
  assert.equal(isBetween(11, 1, 10), false, `isBetween(11, 1, 10) hat ${isBetween(11, 1, 10)} zurückgegeben, erwartet false`);
  assert.equal(isBetween(0, 1, 10), false, `isBetween(0, 1, 10) hat ${isBetween(0, 1, 10)} zurückgegeben, erwartet false`);
});

package.json

{
  "type": "module"
}

package.json sagt Node.js, dass die .js-Dateien Module sind; lassen Sie die Datei im Ordner.

Programm ausführen:

node main.js

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

node --test
learnrun.js herunterladen

Übung 2 von 2

Scope und eine Closure

total(prices) soll die Preise addieren und die Summe zurückgeben, doch der Aufruf bricht mit ReferenceError: sum is not defined ab. Verschieben Sie eine Zeile, damit sum lange genug lebt. makeMultiplier(factor) soll eine Funktion zurückgeben, die ihr Argument mit factor multipliziert, sodass makeMultiplier(3) eine Verdreifachungsfunktion liefert. Der Startcode ignoriert factor. Lassen Sie den zurückgegebenen Pfeil factor verwenden.

Tab rückt ein, Umschalt+Tab rückt aus. Um den Editor mit der Tastatur zu verlassen, drücken Sie Esc und dann Tab.

Beim ersten Ausführen lädt Ihr Browser den JavaScript-Runner herunter (bis zu 0.1 MB) und speichert ihn im Cache. Ihr Code läuft in der eigenen Engine Ihres Browsers und bleibt auf Ihrem Gerät.

Hinweise
  1. Hinweis 1

    Führen Sie die Tests aus: total bricht mit einem ReferenceError ab. Wo wird sum deklariert, und wo wird es gelesen?

  2. Hinweis 2

    Ein let gehört zu den geschweiften Klammern um ihn herum. sum muss vor der Schleife im Funktionsrumpf deklariert werden, damit return es noch sieht. Dort beginnt es auch nur einmal bei 0.

  3. Hinweis 3

    In makeMultiplier kann der Pfeil factor verwenden, weil er in der Funktion erzeugt wurde: (n) => n * factor.

Eine Lösung zeigen

Ein möglicher Lösungsweg. Ihrer kann anders aussehen und trotzdem alle Prüfungen bestehen.

// Add up all prices and return the sum.
export function total(prices) {
  let sum = 0;
  for (const price of prices) {
    sum += price;
  }
  return sum;
}

// Return a function that multiplies its argument by factor.
export function makeMultiplier(factor) {
  return (n) => n * factor;
}
Auf dem eigenen Computer ausführen

Installieren Sie ECMAScript 2026 oder neuer. Speichern Sie diese Dateien in einem Ordner, öffnen Sie dort ein Terminal und führen Sie die Befehle unten aus.

main.js

// Add up all prices and return the sum.
export function total(prices) {
  for (const price of prices) {
    let sum = 0;
    sum += price;
  }
  return sum;
}

// Return a function that multiplies its argument by factor.
export function makeMultiplier(factor) {
  return (n) => n * 2;
}

main.test.js

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {total, makeMultiplier} from './main.js';

test('total([2, 3, 5]) gibt 10 zurück', () => {
  const got = total([2, 3, 5]);
  assert.equal(got, 10, `total([2, 3, 5]) hat ${got} zurückgegeben, erwartet 10`);
});

test('die Summe einer leeren Liste ist 0', () => {
  const got = total([]);
  assert.equal(got, 0, `total([]) hat ${got} zurückgegeben, erwartet 0`);
});

test('makeMultiplier(3) gibt eine Verdreifachungsfunktion zurück', () => {
  const triple = makeMultiplier(3);
  assert.equal(typeof triple, 'function', `makeMultiplier(3) hat ${typeof triple} zurückgegeben, erwartet eine Funktion`);
  assert.equal(triple(4), 12, `makeMultiplier(3)(4) hat ${triple(4)} zurückgegeben, erwartet 12`);
});

test('zwei Multiplikatoren behalten ihren eigenen Faktor', () => {
  const triple = makeMultiplier(3);
  const half = makeMultiplier(0.5);
  assert.equal(half(10), 5, `makeMultiplier(0.5)(10) hat ${half(10)} zurückgegeben, erwartet 5`);
  assert.equal(triple(2), 6, `makeMultiplier(3)(2) hat ${triple(2)} zurückgegeben, erwartet 6`);
});

package.json

{
  "type": "module"
}

package.json sagt Node.js, dass die .js-Dateien Module sind; lassen Sie die Datei im Ordner.

Programm ausführen:

node main.js

Prüfungen ausführen (learnrun.js muss im selben Ordner liegen):

node --test
learnrun.js herunterladen

Häufige Fehler

Ein Objektliteral ohne runde Klammern

const makePoint = (x, y) => { x: x, y: y };
console.log(makePoint(1, 2));

Was Node.js ausgibt

SyntaxError: Unexpected token ':'

Warum, und die Lösung

Geschweifte Klammern direkt nach => beginnen immer einen Blockrumpf. In einem Block ist x: ein Label, und das Komma mit dem zweiten y: ergibt keinen Sinn, also kann die Datei nicht gelesen werden und nichts läuft. Mit nur einem Schlüssel gibt es gar keinen Fehler: Der Pfeil gibt still undefined zurück. Setzen Sie das Objekt in runde Klammern: (x, y) => ({x: x, y: y}).

Ein let nach dem Ende seines Blocks verwenden

const prices = [4, 6];
for (const price of prices) {
  let sum = 0;
  sum += price;
}
console.log(sum);

Was Node.js ausgibt

ReferenceError: sum is not defined

Warum, und die Lösung

sum ist im Schleifenrumpf deklariert, existiert also nur innerhalb dieser Klammern, und bei jedem Durchlauf entsteht ein neues sum mit 0. Nach der Schleife ist der Name verschwunden. Deklarieren Sie ihn vor der Schleife, in dem Scope, in dem Sie ihn am Ende brauchen: let sum = 0; über dem for.

Ein Blockrumpf ohne return

const shout = (text) => {
  text.toUpperCase() + "!";
};
console.log(shout("hi").length);

Was Node.js ausgibt

TypeError: Cannot read properties of undefined (reading 'length')

Warum, und die Lösung

Mit geschweiften Klammern hat der Pfeil einen Blockrumpf, und ein Blockrumpf gibt nur zurück, was eine return-Anweisung liefert. Hier gibt es keine, also ist shout("hi") undefined, und .length von undefined zu lesen schlägt fehl. Schreiben Sie return text.toUpperCase() + "!"; oder lassen Sie die geschweiften Klammern für einen kurzen Rumpf weg: (text) => text.toUpperCase() + "!".

JavaScript im Browser: die eigene Engine Ihres Browsers in einem abgeschotteten Worker. Syntaxfehler findet acorn 8.18.0, MIT. Lizenz und Quellcode

Abschlussquiz

5 Fragen, ohne Hinweise. Ab 80 % ist die Lektion abgeschlossen.

Erledigen Sie zuerst alle Aufgaben oben, um das Abschlussquiz freizuschalten.

Problem melden

Etwas ist falsch oder unklar? Beschreiben Sie es kurz, dann wird es geprüft und korrigiert.

#

Mindestens 20 Zeichen.

Nur, wenn Sie eine Antwort wünschen.

Kernideen

Pfeilfunktionen: kurze Funktionsausdrücke

Eine Pfeilfunktion ist eine kürzere Schreibweise für einen Funktionsausdruck: const double = (n) => n * 2;. Beim kurzen Rumpf wird der Ausdruck nach => automatisch zurückgegeben, ohne das Schlüsselwort return. Bei einem Blockrumpf in geschweiften Klammern, (n) => { const d = n * 2; return d; }, müssen Sie return schreiben, sonst liefert der Aufruf undefined. Eine Falle: Geschweifte Klammern direkt nach => beginnen immer einen Block, daher gibt () => { name: "Ada" } undefined zurück. Um ein Objektliteral zurückzugeben, setzen Sie es in runde Klammern: () => ({name: "Ada"}). Als Callbacks sind Pfeile praktisch: printEach(prices, (p) => p * 2). Ein eigenes this haben sie nicht; das erklärt Modul A3.

Scope: wo ein Name gilt

Ein let oder const gehört zum nächsten Paar geschweifter Klammern um ihn herum, seinem Block: einem if, einem Schleifenrumpf, einem Funktionsrumpf. Außerhalb dieser Klammern gibt es den Namen nicht, und ihn zu lesen ergibt ReferenceError: sum is not defined. Ein Name auf oberster Ebene von main.js liegt im Modul-Scope und gilt in der ganzen Datei. Scopes sind geschachtelt wie Kisten: Innerer Code kann die Namen aller umgebenden Scopes lesen, äußerer Code aber nicht in einen inneren Scope hineinsehen. Deklariert ein innerer Scope denselben Namen noch einmal, verschattet er den äußeren: Innen gilt der innere Wert, außen bleibt der äußere unberührt.

Closures: Funktionen merken sich, wo sie entstanden sind

Eine Funktion kann die Variablen des Scopes verwenden, in dem sie erzeugt wurde, auch wenn dieser Scope schon beendet ist. In function makeGreeter(greeting) { return (name) => `${greeting}, ${name}!`; } kennt der zurückgegebene Pfeil greeting noch, nachdem makeGreeter zurückgekehrt ist. Diese Verbindung aus einer Funktion und den Variablen um sie herum heißt Closure. Jeder Aufruf von makeGreeter erzeugt ein neues greeting, daher liefern makeGreeter("Hello") und makeGreeter("Hi") zwei Funktionen mit eigenen Werten. Eine Closure liest die Variable selbst, keine Kopie: Ändert sich die Variable später, sieht die Funktion den neuen Wert. Lektion B4.5 baut darauf Zähler.

Quellen

Zuletzt geprüft am 3. Oktober 2026