mitmario.dev

Funktionen als Werte

JavaScript Im Browser 3 Min Lesezeit 4 BeispieleLektion 7 von 9

Bis hierhin waren Funktionen etwas, das man aufruft. Jetzt kommt die Wendung: Eine Funktion ist selbst ein Wert, und das ändert, was man mit ihr machen kann.

Diese Lektion steht bewusst vor den Arrays. map, filter und reduce in Abschnitt 6 bekommen alle eine Funktion übergeben. Wer das dort zum ersten Mal sieht, lernt eine Schreibweise auswendig statt einer Idee.

Ein Wert wie eine Zahl

Eine Funktion ist ein Wert wie jeder andere
function verdoppeln(n) {
  return n * 2;
}

// Einer Variablen zuweisen: kein Aufruf, nur ein zweiter Name.
const malZwei = verdoppeln;
console.log("Über den zweiten Namen:", malZwei(21));

// Ihren Typ nachsehen wie bei jedem anderen Wert.
console.log("typeof verdoppeln:", typeof verdoppeln);
console.log("typeof 42:", typeof 42);

// In eine Liste legen und daraus aufrufen.
const rechnungen = [verdoppeln, (n) => n * n];
console.log("Aus der Liste:", rechnungen[0](5), rechnungen[1](5));

Alles, was du mit einer Zahl tun kannst, kannst du mit einer Funktion tun. Sie einer Variablen zuweisen, ihren Typ abfragen, sie in eine Liste legen, sie an eine andere Funktion übergeben, sie aus einer Funktion zurückgeben.

typeof sagt dazu "function", und das ist der einzige Hinweis darauf, dass sie etwas Besonderes ist. Ansonsten liegt sie da wie jeder andere Wert.

Der zweite Name im Beispiel ist keine Kopie. Beide Namen zeigen auf dieselbe Funktion, so wie zwei Schilder auf dasselbe Haus zeigen können.

Ein Klammerpaar Unterschied

Mit Klammern und ohne
function wuerfeln() {
  return 4;
}

// Ohne Klammern: die Funktion selbst.
console.log("Ohne Klammern:", typeof wuerfeln);

// Mit Klammern: das Ergebnis.
console.log("Mit Klammern:", typeof wuerfeln());

// Und der Fehler, der daraus entsteht. spaeter bekommt hier keine
// Funktion, sondern die Zahl 4, und mit einer Zahl kann es nichts
// anfangen.
function spaeter(aufgabe) {
  console.log("Ich rufe jetzt auf:", aufgabe());
}

spaeter(wuerfeln);
spaeter(wuerfeln());

Das hier ist die Stelle, an der es schiefgeht, und zwar zuverlässig.

wuerfeln ist die Funktion selbst. Du reichst das Rezept weiter, jemand anderes kocht später.

wuerfeln() ist ihr Ergebnis. Du kochst sofort und reichst den Teller weiter.

Beides ist gültiger Code, und deshalb bekommst du keine Fehlermeldung an der Stelle, an der du dich vertippt hast. Der Fehler taucht später auf, an einer ganz anderen Zeile, und heißt dann aufgabe is not a function.

Lektion 5.1 hat den Fall schon einmal gestreift, dort war das Ergebnis nur, dass nichts passiert. Hier ist er die halbe Lektion. Und in Abschnitt 12, bei den Klicks auf einen Knopf, ist er der mit Abstand häufigste Fehler überhaupt: Wer dort die Klammern setzt, ruft die Funktion sofort auf, statt sie für den Klick zu hinterlegen.

Der Callback

Der Callback
// wende kennt die Rechnung nicht. Sie bekommt sie übergeben und
// ruft sie zum richtigen Zeitpunkt auf.
function wende(zahl, rechnung) {
  return rechnung(zahl);
}

const verdoppeln = (n) => n * 2;
const quadrat = (n) => n * n;

console.log(wende(5, verdoppeln));
console.log(wende(5, quadrat));

// Die übergebene Funktion braucht keinen Namen, wenn sie nur an
// dieser einen Stelle gebraucht wird.
console.log(wende(5, (n) => n + 100));

// Dieselbe Idee mit einem eigenen Namen für die Stelle: dreimal
// dasselbe tun und jedes Mal melden, wie oft schon.
function dreimal(was) {
  for (let i = 1; i <= 3; i++) {
    was(i);
  }
}

dreimal((nummer) => console.log("Durchlauf", nummer));

Eine Funktion, die du jemand anderem gibst, damit er sie zum richtigen Zeitpunkt aufruft, heißt Callback. Auf Deutsch würde man „Rückruf” sagen, aber niemand tut das.

Der Nutzen ist eine saubere Arbeitsteilung. wende kümmert sich darum, wann und womit gerechnet wird. Was gerechnet wird, weiß sie nicht und muss sie nicht wissen. Damit ist dieselbe Funktion für beliebig viele Rechnungen brauchbar.

Braucht die übergebene Funktion nur an dieser einen Stelle einen Platz, gibt man ihr keinen Namen und schreibt sie direkt in die Klammern. Das ist die Form, die du ab Abschnitt 6 überall sehen wirst.

Beachte im letzten Block, dass der Callback ein Argument bekommt. Wer eine Funktion entgegennimmt, entscheidet auch, womit er sie aufruft, und das ist beim Lesen fremden Codes die erste Frage: Was bekommt mein Callback eigentlich übergeben?

Funktionen, die Funktionen bauen

Eine Funktion, die eine Funktion zurückgibt
// malN gibt keine Zahl zurück, sondern eine Funktion. Die merkt
// sich n, genau wie der Zähler aus Lektion 5.6.
function malN(n) {
  return (zahl) => zahl * n;
}

const malDrei = malN(3);
const malZehn = malN(10);

console.log("malDrei(7):", malDrei(7));
console.log("malZehn(7):", malZehn(7));

// Beides in einem Rutsch geht auch, sieht aber ungewohnt aus:
// die erste Klammer baut die Funktion, die zweite ruft sie auf.
console.log("Direkt:", malN(3)(7));

// Praktischer Nutzen: eine Vorlage, aus der man Varianten baut.
const prozentAbzug = (prozent) => (preis) => preis - (preis * prozent) / 100;
const minusZehn = prozentAbzug(10);

console.log("100 Euro minus 10 Prozent:", minusZehn(100));

Die Umkehrung: Eine Funktion darf eine Funktion zurückgeben.

malN(3) rechnet nichts aus. Es liefert eine neue Funktion, die sich die 3 gemerkt hat, genau wie der Zähler aus Lektion 5.6 sich seinen Stand merkt. Erst der Aufruf dieser neuen Funktion rechnet.

Deshalb sieht malN(3)(7) so ungewohnt aus. Die erste Klammer baut die Funktion, die zweite ruft sie auf. In der Praxis schreibt man das meistens in zwei Schritten und gibt der gebauten Funktion einen Namen, denn dann liest sich der Aufruf danach wie jeder andere.

Der Nutzen ist eine Vorlage, aus der man Varianten baut: einmal festlegen, was gleich bleibt, und den Rest offen lassen. Genau das tust du in der Challenge.

Zum Mitnehmen

machDas reicht die Funktion weiter, machDas() reicht ihr Ergebnis weiter. Ein Klammerpaar Unterschied, zwei völlig verschiedene Dinge.

Jetzt du

Basis Konto, kostenlos

Zu dieser Lektion gehört eine Aufgabe. Du schreibst den Code selbst, und nach jedem Lauf sagt dir eine Prüfliste, was schon stimmt.

Dafür brauchst du das Basis Konto. Es kostet nichts, und ein Passwort gibt es auch nicht.

Was in dieser Lektion steckt

  • Artikel mit 4 Beispielen zum Ausprobieren

    Steht hier, ohne Konto lesbar.

  • Aufgabe im Editor, direkt im Browser geprüft

    Öffnet sich mit dem Basis Konto.