Start · Sprachen · JavaScript · Referenz · Pfeilfunktionen (Arrow Function Expressions)

Pfeilfunktionen (Arrow Function Expressions)

Keyword

Pfeilfunktionen sind eine kurze Schreibweise für Funktionsausdrücke. Sie haben kein eigenes <code>this</code>, <code>arguments</code>, <code>super</code> und kein <code>new.target</code>.

seit JavaScript ES2015 Kategorie: syntax

Signatur

(param1, param2, …, paramN) =&gt; expression | (param1, …, paramN) =&gt; { statements }

Beschreibung

Eine Pfeilfunktion (Arrow Function Expression) ist eine kürzere Alternative zum klassischen Funktionsausdruck mit function. Besteht der Rumpf nur aus einem Ausdruck (Kurzform), wird dessen Wert automatisch zurückgegeben, ein return ist dann nicht nötig. Mit geschweiften Klammern (Blockform) verhält sich der Rumpf wie ein normaler Funktionsrumpf, und ein Rückgabewert braucht ein ausdrückliches return.

Der wichtigste Unterschied betrifft die Bedeutung: Pfeilfunktionen haben kein eigenes this, kein eigenes arguments, kein super und kein new.target. Diese Werte übernehmen sie lexikalisch aus dem umgebenden Gültigkeitsbereich. Deshalb eignen sie sich besonders für Callbacks wie map, filter, setTimeout, Promise-Ketten oder Event-Handler innerhalb von Klassen, wenn dort das this der äußeren Methode gebraucht wird.

Es gibt bewusste Einschränkungen: Pfeilfunktionen lassen sich nicht als Konstruktor mit new aufrufen und haben keine prototype-Eigenschaft. Sie können keine Generatoren sein, weil yield im Rumpf nicht erlaubt ist. Ihr this lässt sich auch mit call, apply oder bind nicht ändern. Als Objektmethoden, die auf das eigene Objekt über this zugreifen sollen, sind sie deshalb ungeeignet.

Asynchrone Pfeilfunktionen schreibt man mit vorangestelltem async, zum Beispiel async (url) => { … }. Parameter können Standardwerte, Restparameter und Destrukturierung verwenden. Die Klammern um die Parameter darf man nur bei genau einem einfachen Parameter weglassen.

Parameter

Name Typ Default Beschreibung
$param Bezeichner Ein einzelner einfacher Parameter. Hier dürfen die Klammern fehlen: x => x * 2.
$(param1, …, paramN) Parameterliste Keiner oder mehrere Parameter in runden Klammern. Ohne Parameter sind leere Klammern Pflicht: () => 42.
$(a = 1, ...rest, { x, y }) Standardwerte | Restparameter | Destrukturierung Standardwerte, Restparameter und destrukturierte Parameter sind erlaubt. In diesen Fällen sind Klammern immer Pflicht.
$expression Ausdruck Kurzform: Der Wert des Ausdrucks wird automatisch zurückgegeben. Ein Objektliteral muss in Klammern stehen: () => ({ a: 1 }).
${ statements } Anweisungsblock Blockform: ein normaler Funktionsrumpf. Ohne return ist der Rückgabewert undefined.

Rückgabewert

Typ
Function
Beschreibung
Der Ausdruck ergibt ein Funktionsobjekt. Beim Aufruf liefert es in der Kurzform den Wert des Ausdrucks, in der Blockform den Wert von return (sonst undefined). Mit async liefert der Aufruf ein Promise.

Beispiele

Kurzform in Array-Methoden

const preise = [19.99, 5.5, 42];
const brutto = preise.map((p) => +(p * 1.19).toFixed(2));
const teuer = brutto.filter((p) => p > 20);
const summe = brutto.reduce((acc, p) => acc + p, 0);

console.log(brutto);
console.log(teuer);
console.log(summe.toFixed(2));
[23.79, 6.55, 49.98] [23.79, 49.98] 80.32

Objektliteral zurückgeben: Klammern nötig

const users = ['anna', 'ben'];

// Falsch: {} wird als Block gelesen, Ergebnis ist undefined
const falsch = users.map((name) => { name: name });

// Richtig: Objektliteral in runde Klammern setzen
const richtig = users.map((name, i) => ({ id: i + 1, name }));

console.log(falsch);
console.log(richtig);
[undefined, undefined] [{ id: 1, name: 'anna' }, { id: 2, name: 'ben' }]

Lexikalisches this in Klassen

class Countdown {
  constructor(start) {
    this.wert = start;
  }

  starten() {
    const id = setInterval(() => {
      // this bezieht sich auf die Countdown-Instanz
      console.log(this.wert--);
      if (this.wert < 0) clearInterval(id);
    }, 1000);
  }
}

new Countdown(3).starten();
3 2 1 0

Async-Pfeilfunktion mit Destrukturierung und Standardwert

const ladeBenutzer = async ({ id, basis = 'https://jsonplaceholder.typicode.com' }) => {
  const res = await fetch(`${basis}/users/${id}`);
  if (!res.ok) throw new Error(`HTTP ${res.status}`);
  const { name, email } = await res.json();
  return { name, email };
};

ladeBenutzer({ id: 1 })
  .then((user) => console.log(user))
  .catch((err) => console.error(err.message));
{ name: 'Leanne Graham', email: 'Sincere@april.biz' }

Fallstrick: Pfeilfunktion als Objektmethode

const zaehler = {
  stand: 0,
  erhoehenPfeil: () => {
    // this ist NICHT zaehler, sondern das äußere this
    return typeof this?.stand;
  },
  erhoehen() {
    return ++this.stand;
  },
};

console.log(zaehler.erhoehenPfeil());
console.log(zaehler.erhoehen());
undefined 1

Klassenfeld als gebundener Event-Handler

class Button {
  klicks = 0;

  // Klassenfeld mit Pfeilfunktion: this bleibt immer die Instanz
  handleClick = () => {
    this.klicks++;
    console.log(`Geklickt: ${this.klicks}`);
  };

  mount(el) {
    el.addEventListener('click', this.handleClick);
  }
}

new Button().mount(document.querySelector('#speichern'));
Geklickt: 1 (nach dem ersten Klick)

// Wichtig · Fallstricke

  • Kein eigenes this: call, apply und bind ändern das this einer Pfeilfunktion nicht. Das erste Argument wird ignoriert.
  • Kein arguments: Innerhalb einer Pfeilfunktion zeigt arguments auf die umgebende normale Funktion, falls es eine gibt, sonst entsteht ein ReferenceError. Stattdessen Restparameter verwenden: (...args) => args.length.
  • Nicht mit new aufrufbar: new (() => {})() wirft einen TypeError. Es gibt keine prototype-Eigenschaft.
  • Keine Generatoren: yield ist im Rumpf nicht erlaubt, und eine Syntax *() => gibt es nicht.
  • Zeilenumbruch: Vor => darf kein Zeilenumbruch stehen. (a, b)\n=> a + b ist ein SyntaxError.
  • Vorrang der Operatoren: Eine Pfeilfunktion wird nicht wie ein normaler Operator-Ausdruck ausgewertet. a || () => {} ist ungültig, richtig ist a || (() => {}).
  • Keine Hebung (Hoisting): Pfeilfunktionen sind immer Ausdrücke. Wer sie in const speichert, kann sie vor der Definition nicht verwenden (temporale Todeszone).
  • DOM-Event-Handler: Mit addEventListener zeigt this in einer Pfeilfunktion nicht auf das Element. Dafür event.currentTarget verwenden.
  • Klassenfelder mit Pfeilfunktionen erzeugen für jede Instanz eine eigene Funktion und liegen nicht auf dem Prototyp. Das verbraucht mehr Speicher, und super.methode() funktioniert in abgeleiteten Klassen nicht wie gewohnt.
  • Kompatibilität: Pfeilfunktionen laufen in allen modernen Browsern und in Node.js ab Version 4. Der Internet Explorer unterstützt sie nicht.