Arrow Functions in JavaScript
Arrow Functions in JavaScript
Arrow Functions (Pfeilfunktionen) sind die moderne, kompakte Syntax für Funktionen in JavaScript. Sie wurden mit ES6 eingeführt und sind heute der Standard.
Von function zu Arrow
Die Evolution einer Funktion:
// Traditionelle Funktion
function addiere(a, b) {
return a + b;
}
// Funktionsausdruck
const addiere = function(a, b) {
return a + b;
};
// Arrow Function
const addiere = (a, b) => {
return a + b;
};
// Arrow Function - Kurzform
const addiere = (a, b) => a + b;
Alle vier machen das Gleiche, aber die Arrow-Syntax ist kürzer und eleganter.
Die Syntax im Detail
Basis-Syntax
// Mit Funktionskörper (geschweifte Klammern)
const funktion = (parameter) => {
// Code hier
return ergebnis;
};
// Kurzform (nur ein Ausdruck, implizites return)
const funktion = (parameter) => ausdruck;
Parameter-Varianten
// Keine Parameter - leere Klammern nötig
const hallo = () => "Hallo Welt!";
// Ein Parameter - Klammern optional
const verdopple = x => x * 2;
const verdopple = (x) => x * 2; // Auch OK
// Mehrere Parameter - Klammern nötig
const addiere = (a, b) => a + b;
// Default-Parameter
const gruss = (name = "Gast") => `Hallo ${name}!`;
// Rest-Parameter
const summe = (...zahlen) => zahlen.reduce((a, b) => a + b, 0);
Rückgabe-Varianten
// Implizites return (ein Ausdruck)
const quadrat = x => x * x;
const istGerade = n => n % 2 === 0;
// Explizites return (Funktionskörper)
const berechne = (a, b) => {
const ergebnis = a * b;
return ergebnis;
};
// Objekt zurückgeben - Klammern nötig!
const erstellePerson = (name, alter) => ({ name, alter });
// ❌ Ohne Klammern - wird als Funktionskörper interpretiert
const falsch = (name) => { name: name }; // undefined!
Praktische Beispiele
Einfache Transformationen
// Zahlen verdoppeln
const zahlen = [1, 2, 3, 4, 5];
const verdoppelt = zahlen.map(x => x * 2);
// [2, 4, 6, 8, 10]
// Strings in Großbuchstaben
const namen = ["anna", "ben", "clara"];
const gross = namen.map(name => name.toUpperCase());
// ["ANNA", "BEN", "CLARA"]
// Objekte transformieren
const users = [
{ id: 1, name: "Max", email: "max@test.de" },
{ id: 2, name: "Lisa", email: "lisa@test.de" }
];
const emails = users.map(user => user.email);
// ["max@test.de", "lisa@test.de"]
Filtern
const zahlen = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Gerade Zahlen
const gerade = zahlen.filter(n => n % 2 === 0);
// [2, 4, 6, 8, 10]
// Größer als 5
const gross = zahlen.filter(n => n > 5);
// [6, 7, 8, 9, 10]
// Produkte unter 50€
const produkte = [
{ name: "Buch", preis: 15 },
{ name: "Laptop", preis: 999 },
{ name: "Stift", preis: 2 }
];
const guenstig = produkte.filter(p => p.preis < 50);
// [{ name: "Buch", preis: 15 }, { name: "Stift", preis: 2 }]
Sortieren
const zahlen = [3, 1, 4, 1, 5, 9, 2, 6];
// Aufsteigend
zahlen.sort((a, b) => a - b);
// [1, 1, 2, 3, 4, 5, 6, 9]
// Absteigend
zahlen.sort((a, b) => b - a);
// [9, 6, 5, 4, 3, 2, 1, 1]
// Nach Eigenschaft sortieren
const personen = [
{ name: "Clara", alter: 25 },
{ name: "Anna", alter: 30 },
{ name: "Ben", alter: 20 }
];
// Nach Alter
personen.sort((a, b) => a.alter - b.alter);
// Nach Name
personen.sort((a, b) => a.name.localeCompare(b.name));
Reduce
const zahlen = [1, 2, 3, 4, 5];
// Summe
const summe = zahlen.reduce((acc, curr) => acc + curr, 0);
// 15
// Maximum
const max = zahlen.reduce((a, b) => a > b ? a : b);
// 5
// Objekt bauen
const namen = ["Anna", "Ben", "Clara"];
const laengen = namen.reduce((obj, name) => {
obj[name] = name.length;
return obj;
}, {});
// { Anna: 4, Ben: 3, Clara: 5 }
Arrow Functions mit this
Der wichtigste Unterschied zu normalen Funktionen: Arrow Functions haben kein eigenes this.
Das Problem mit normalem this
const person = {
name: "Max",
hobbies: ["Lesen", "Gaming", "Sport"],
// ❌ Problem: this ist undefined in der Callback-Funktion
zeigeHobbies: function() {
this.hobbies.forEach(function(hobby) {
console.log(this.name + " mag " + hobby);
// this.name ist undefined!
});
}
};
person.zeigeHobbies();
// undefined mag Lesen
// undefined mag Gaming
// undefined mag Sport
Die Lösung: Arrow Functions
const person = {
name: "Max",
hobbies: ["Lesen", "Gaming", "Sport"],
// ✅ Arrow Function erbt this vom umgebenden Scope
zeigeHobbies: function() {
this.hobbies.forEach(hobby => {
console.log(this.name + " mag " + hobby);
// this zeigt auf person!
});
}
};
person.zeigeHobbies();
// Max mag Lesen
// Max mag Gaming
// Max mag Sport
this - Vergleich
const obj = {
wert: 42,
// Normale Funktion - eigenes this
normal: function() {
console.log(this.wert); // 42
},
// Arrow Function - this vom Parent
arrow: () => {
console.log(this.wert); // undefined (this ist window/global)
},
// Normale Funktion mit Arrow-Callback
delayed: function() {
setTimeout(() => {
console.log(this.wert); // 42 - Arrow erbt this
}, 1000);
},
// Normale Funktion mit normalem Callback
delayedProblem: function() {
setTimeout(function() {
console.log(this.wert); // undefined - eigenes this
}, 1000);
}
};
Wann normale Funktionen verwenden?
Als Objekt-Methoden
// ❌ Arrow Function als Methode - this funktioniert nicht
const person = {
name: "Max",
gruss: () => {
console.log(`Hallo, ich bin ${this.name}`);
// this.name ist undefined!
}
};
// ✅ Normale Funktion als Methode
const person = {
name: "Max",
gruss() {
console.log(`Hallo, ich bin ${this.name}`);
}
};
Als Konstruktor
// ❌ Arrow Function kann nicht als Konstruktor verwendet werden
const Person = (name) => {
this.name = name;
};
// new Person("Max"); // TypeError!
// ✅ Normale Funktion als Konstruktor
function Person(name) {
this.name = name;
}
new Person("Max"); // OK
Mit arguments-Objekt
// ❌ Arrow Function hat kein arguments
const arrow = () => {
console.log(arguments); // ReferenceError!
};
// ✅ Normale Funktion hat arguments
function normal() {
console.log(arguments); // OK
}
// ✅ Oder Rest-Parameter verwenden
const mitRest = (...args) => {
console.log(args); // OK
};
Event Handler
// ✅ Arrow Function für einfache Handler
button.addEventListener("click", () => {
console.log("Geklickt!");
});
// ⚠️ Aber: this zeigt nicht auf das Element!
button.addEventListener("click", () => {
console.log(this); // window, nicht button!
});
// ✅ Wenn du das Element brauchst: event.target
button.addEventListener("click", (event) => {
console.log(event.target); // Das Button-Element
});
// ✅ Oder normale Funktion wenn this nötig
button.addEventListener("click", function() {
console.log(this); // Das Button-Element
});
Sofort ausführen (IIFE)
// Arrow Function IIFE
(() => {
const privat = "Geheim";
console.log("Sofort ausgeführt!");
})();
// Mit Parameter
((name) => {
console.log(`Hallo ${name}!`);
})("Welt");
Verkettung und Composition
const zahlen = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// Methoden verketten
const ergebnis = zahlen
.filter(n => n % 2 === 0) // Gerade: [2,4,6,8,10]
.map(n => n * n) // Quadriert: [4,16,36,64,100]
.filter(n => n > 20) // > 20: [36,64,100]
.reduce((a, b) => a + b, 0); // Summe: 200
console.log(ergebnis); // 200
Currying mit Arrow Functions
// Ohne Currying
const addiere = (a, b) => a + b;
addiere(2, 3); // 5
// Mit Currying - Funktion gibt Funktion zurück
const addiere = a => b => a + b;
const addiereFuenf = addiere(5);
addiereFuenf(3); // 8
addiereFuenf(10); // 15
// Direkt aufrufen
addiere(2)(3); // 5
// Praktisches Beispiel: Logger
const log = prefix => message => console.log(`[${prefix}] ${message}`);
const errorLog = log("ERROR");
const infoLog = log("INFO");
errorLog("Verbindung fehlgeschlagen"); // [ERROR] Verbindung fehlgeschlagen
infoLog("Server gestartet"); // [INFO] Server gestartet
Best Practices
1. Kurzform für einfache Ausdrücke
// ✅ Gut
const verdopple = x => x * 2;
const istGerade = n => n % 2 === 0;
// ❌ Unnötig verbose
const verdopple = (x) => { return x * 2; };
2. Klammern bei Objekten
// ✅ Gut - Klammern um Objekt
const erstelle = (name, alter) => ({ name, alter });
// ❌ Fehler
const erstelle = (name, alter) => { name, alter };
3. Konsistente Parameterklammern
// Konsistent mit Klammern (empfohlen für Teams)
const a = (x) => x * 2;
const b = (x, y) => x + y;
const c = () => "hallo";
// Oder konsistent minimalistisch
const a = x => x * 2;
const b = (x, y) => x + y;
const c = () => "hallo";
Zusammenfassung
| Feature | Arrow Function | Normale Funktion |
|---|---|---|
| Syntax | () => {} | function() {} |
| this | Vom Parent geerbt | Eigenes this |
| arguments | Nicht verfügbar | Verfügbar |
| Konstruktor | ❌ | ✅ |
| Methoden | ⚠️ Problematisch | ✅ |
| Callbacks | ✅ Ideal | ⚠️ this-Probleme |
// Faustregeln:
// → Callbacks, map/filter/reduce → Arrow
// → Objekt-Methoden → Normale Funktion
// → Konstruktoren → Normale Funktion
// → Alles andere → Arrow (kürzer, moderner)
Übung: Schreibe eine Funktion pipe die mehrere Funktionen verkettet: pipe(addOne, double, square)(5) sollte ((5+1)*2)^2 = 144 ergeben.