Arrow Functions sind seit ES2015 die kompakteste Form, eine Funktion in JavaScript zu schreiben — (a, b) => a + b ist eine vollwertige Funktion. Aber Arrows sind keine bloße Kurzschreibweise: sie haben kein eigenes this, kein arguments-Objekt, keinen prototype, und können nicht mit new aufgerufen werden. Diese Unterschiede machen sie zur idealen Wahl für Callbacks innerhalb von Methoden — und zur falschen Wahl für Object-Methoden, die this brauchen. Dieser Artikel zeigt die Syntax-Varianten, klärt die Unterschiede zu klassischen Funktionen und nennt die Stellen, an denen Arrows nicht passen.

Syntax-Varianten

Arrow Functions sind in mehreren Schreibweisen erlaubt, je nach Anzahl der Parameter und Body-Form.

JavaScript arrow-syntax.js
// Ohne Parameter: leere Klammern Pflicht
const ping = () => 'pong';
console.log(ping());

// Ein Parameter: Klammern optional
const verdoppeln = x => x * 2;
console.log(verdoppeln(5));

// Mehrere Parameter: Klammern Pflicht
const summe = (a, b) => a + b;
console.log(summe(2, 3));

// Mehr als ein Statement: geschweifte Klammern + explicit return
const beschreiben = (name, alter) => {
    const text = `${name} ist ${alter} Jahre`;
    return text;
};
console.log(beschreiben('Anna', 30));

// Object-Literal zurückgeben: in Klammern wickeln
const erstelleUser = name => ({ name, aktiv: true });
console.log(erstelleUser('Bob'));
Output
pong
10
5
Anna ist 30 Jahre
{ name: 'Bob', aktiv: true }

Die letzte Variante ist eine berüchtigte Falle: name => { name } interpretiert die Engine als Block mit Label name, nicht als Objekt-Literal — Rückgabe undefined. Die Klammer-Wicklung name => ({ name }) macht es eindeutig zur Expression.

Lexical this — kein eigenes Binding

Der wichtigste Unterschied zu klassischen Funktionen: Arrow Functions haben kein eigenes this. this zeigt auf das, was im umgebenden Scope galt — dort, wo die Arrow Function geschrieben wurde.

JavaScript lexical-this.js
const obj = {
    wert: 42,
    klassisch: function() {
        setTimeout(function() {
            console.log('classic:', this.wert); // undefined — this ist global/undefined
        }, 0);
    },
    arrow: function() {
        setTimeout(() => {
            console.log('arrow:  ', this.wert); // 42 — this kommt von arrow()
        }, 0);
    },
};

obj.klassisch();
obj.arrow();
Output
classic: undefined
arrow:   42

Das macht Arrows zur idealen Wahl für Inner-Callbacks innerhalb von Methoden — sie behalten den this-Bezug der äußeren Methode, ohne dass bind(this) oder const self = this nötig wäre.

Kein arguments-Objekt

Klassische Funktionen haben das implizite arguments-Objekt (Array-like mit allen übergebenen Argumenten). Arrows haben das nicht — der Versuch, arguments darin zu lesen, greift auf das arguments der umgebenden Funktion zurück (oder wirft ReferenceError, wenn keines existiert).

JavaScript kein-arguments.js
function klassisch() {
    console.log(arguments.length, [...arguments]);
}
klassisch(1, 2, 3); // 3 [ 1, 2, 3 ]

// Arrow: arguments existiert nicht
const arrow = () => {
    // console.log(arguments); // ReferenceError im Module-Scope
};

// Alternative: Rest-Parameter
const restArrow = (...args) => {
    console.log(args.length, args);
};
restArrow(1, 2, 3); // 3 [ 1, 2, 3 ]
Output
3 [ 1, 2, 3 ]
3 [ 1, 2, 3 ]

In der Praxis ist das selten ein Nachteil — Rest-Parameter (...args) sind ohnehin der modernere Weg, variadic Funktionen zu schreiben. Sie liefern ein echtes Array, nicht ein Array-like-Object.

Kein new möglich

Arrow Functions sind nicht konstruierbar. new arrow() wirft TypeError. Sie haben auch keinen prototype-Property.

JavaScript kein-new.js
const Tier = (name) => { this.name = name; };

try {
    const t = new Tier('Bello');
} catch (e) {
    console.log('Fehler:', e.message);
}

// Klassische Funktion ist konstruierbar
function TierK(name) { this.name = name; }
const k = new TierK('Bello');
console.log(k.name);

console.log('Arrow prototype:', Tier.prototype);   // undefined
console.log('Function prototype:', TierK.prototype); // {} (existiert)
Output
Fehler: Tier is not a constructor
Bello
Arrow prototype: undefined
Function prototype: {}

Für Constructor-Funktionen: klassische Form oder class. Arrows sind nur für „normale" Funktionen gedacht.

Object-Methoden — Arrow ist meist FALSCH

Wer eine Methode auf einem Object definiert und Zugriff auf das Objekt via this braucht, sollte keine Arrow Function nutzen.

JavaScript object-methode-arrow.js
// FALSCH: Arrow als Methode — this zeigt nicht auf obj
const obj1 = {
    name: 'Anna',
    sagHallo: () => {
        console.log('Hallo,', this?.name); // undefined
    },
};
obj1.sagHallo();

// RICHTIG: Methoden-Shorthand
const obj2 = {
    name: 'Anna',
    sagHallo() {
        console.log('Hallo,', this.name); // 'Anna'
    },
};
obj2.sagHallo();
Output
Hallo, undefined
Hallo, Anna

Das ist eine der häufigsten Anfänger-Fehler. Faustregel: Methoden-Shorthand im Object-Literal, Arrow für freie Callback-Funktionen.

Event-Handler — Arrow oft FALSCH

DOM-Event-Handler erwarten typischerweise, dass this auf das Element zeigt. Mit Arrow geht das nicht.

JavaScript event-handler.js
// FALSCH: this zeigt NICHT auf button
button.addEventListener('click', () => {
    this.classList.add('aktiv'); // this ist nicht button
});

// RICHTIG: klassische Funktion
button.addEventListener('click', function() {
    this.classList.add('aktiv'); // this = button
});

// ODER: e.currentTarget statt this
button.addEventListener('click', (e) => {
    e.currentTarget.classList.add('aktiv');
});

Die e.currentTarget-Variante ist heute weit verbreitet, weil sie unabhängig vom Funktions-Typ funktioniert und explizit ist, was gemeint ist.

Class-Felder mit Arrow — Auto-Bind-Pattern

Eine spezielle Anwendung: in einer Klasse als Field definiert, ist eine Arrow Function automatisch an die Instanz gebunden — kein bind(this) nötig.

JavaScript class-arrow-field.js
class Counter {
    wert = 0;

    // Methode — this hängt vom Aufruf-Kontext ab
    incMethode() { this.wert++; }

    // Field mit Arrow — this ist immer die Instanz
    incArrow = () => { this.wert++; };
}

const c = new Counter();
const ref1 = c.incMethode;
const ref2 = c.incArrow;

try {
    ref1();   // TypeError: Cannot read properties of undefined
} catch (e) {
    console.log('Methode entkoppelt:', e.message);
}

ref2();
console.log('Arrow-Field:', c.wert);
Output
Methode entkoppelt: Cannot read properties of undefined (reading 'wert')
Arrow-Field: 1

Nachteil: das Arrow-Field ist pro Instanz neu allokiert — bei vielen Instanzen mehr Speicher als bei einer einzigen Methode am Prototyp. Bei Component-Frameworks (React-Klassen, Web Components) ist das Pattern trotzdem üblich, weil die Bindung-Sicherheit das Speicher-Argument aussticht.

Implicit Return — eleganter als gedacht

Ohne geschweifte Klammern liefert die Arrow Function den Wert des Ausdrucks zurück. Praktisch in Pipelines mit map/filter/reduce.

JavaScript implicit-return.js
const users = [
    { name: 'Anna', alter: 30 },
    { name: 'Bob', alter: 17 },
    { name: 'Chris', alter: 25 },
];

const namen = users
    .filter(u => u.alter >= 18)
    .map(u => u.name)
    .map(n => n.toUpperCase());

console.log(namen); // [ 'ANNA', 'CHRIS' ]

// Ohne Implicit Return wäre das deutlich umständlicher
Output
[ 'ANNA', 'CHRIS' ]

Implicit Return ist genau das, was Funktional-Stil-Code lesbar macht. Eine Filter-Pipeline mit klassischen Funktionen wäre dreimal so lang.

Wann KEINE Arrow nutzen?

Eine kompakte Checkliste:

KontextArrow?Warum
Object-Methode mit thisneinthis ist lexikalisch, nicht das Object
Class-Methode am Prototypneinthis-Binding via Aufruf nötig
Event-Handler, der this=Element willneinthis ist lexikalisch
Constructor (new MyClass())neinArrow ist nicht konstruierbar
Funktion, die arguments brauchtneinhat kein eigenes arguments
Generator (function*)neinArrow kennt kein yield
Inline-Callback (map, filter, then)jakompakt, kein this-Problem
Top-Level kurze Helperjakompakt, eindeutig
Class-Field für auto-bound Handlerjathis = Instanz, kein bind nötig

Besonderheiten

Lexical this — der Hauptgrund für Arrows

Arrow Functions binden this NICHT. Sie übernehmen das this ihres umgebenden Scopes. Das macht sie zur idealen Callback-Form in Methoden — vorher musste man bind(this) oder const self = this nutzen, um den this-Bezug zu retten.

Object-Literal mit nacktem => braucht extra Klammern

x => { name: x } ist nicht „Objekt mit Eigenschaft name", sondern ein Block mit Label name. Rückgabe: undefined. Lösung: x => ({ name: x }) — die äußeren Klammern machen es eindeutig zur Expression.

Kein arguments — aber ...args klappt

Arrows haben kein arguments-Objekt. In Practice kein Verlust, weil ...args als Rest-Parameter ein echtes Array liefert und in jedem Funktionstyp funktioniert. Rest-Parameter sind die moderne Form für variadic Funktionen.

Arrow als Class-Field — Auto-Bind ohne bind

class C { handler = () => this.foo; } bindet handler an die Instanz. Praktisch in React-Class-Components oder Web Components. Nachteil: pro Instanz allokiert, nicht am Prototyp geteilt — bei vielen Instanzen mehr Speicher.

Kein new — Arrow ist NICHT konstruierbar

new arrow() wirft TypeError: arrow is not a constructor. Arrows haben auch keinen prototype-Property. Für Constructor-Pattern: klassische Funktion oder class.

Generators als Arrow nicht möglich

function* hat keine Arrow-Variante. Generators brauchen yield, und das ist syntaktisch nur in function*-Form erlaubt. Wer einen Generator schreiben will, muss klassisch deklarieren.

Async Arrow ist möglich: async () => { await ... }

Im Gegensatz zu Generators gibt es Async Arrow Functions: const f = async () => { await ... }. Verhalten identisch zu async function() bis auf die üblichen Arrow-Unterschiede (this, arguments, new). Sehr verbreitet in modernen Codebasen.

Arrow-Funktion ohne Namen — heuristischer .name

const f = () => ... bekommt f.name === 'f' via ES2015-Heuristik aus der Zuweisung. Bei Higher-Order-Konstruktion oder anonymem Inline-Pass ist .name oft ''. Für reliable Naming gibt es bei Arrows keine „Named Expression"-Variante.

Weiterführende Ressourcen

Externe Quellen

/ Weiter

Zurück zu Funktionen

Zur Übersicht