Funktionen sind ein grundlegender Baustein der JavaScript-Programmierung. Sie ermöglichen die Strukturierung von Code in logische, wiederverwendbare Einheiten und bilden die Basis für komplexere Konzepte wie Objektorientierung und funktionale Programmierung. JavaScript bietet verschiedene Möglichkeiten, Funktionen zu definieren und mit Parametern zu arbeiten, was die Sprache besonders flexibel macht.
Die klassische Art, eine Funktion zu definieren, ist die Funktionsdeklaration (Function Declaration):
function quadrieren(zahl) {
return zahl * zahl;
}Besonderheiten der Funktionsdeklaration:
// Funktionsaufruf vor der Definition - funktioniert dank Hoisting
console.log(willkommen("JavaScript")); // "Willkommen, JavaScript!"
function willkommen(name) {
return "Willkommen, " + name + "!";
}Funktionsdeklarationen eignen sich besonders für zentrale, allgemeine Funktionen einer Anwendung, die an verschiedenen Stellen verwendet werden.
Ein Funktionsausdruck (Function Expression) weist eine Funktion einer Variablen zu:
const quadrieren = function(zahl) {
return zahl * zahl;
};Besonderheiten des Funktionsausdrucks:
// Benannter Funktionsausdruck
const fakultät = function berechneF(n) {
if (n <= 1) return 1;
return n * berechneF(n - 1); // Rekursive Verwendung des internen Namens
};
console.log(fakultät(5)); // 120
// console.log(berechneF(5)); // ReferenceError - Name nur innerhalb der Funktion verfügbarFunktionsausdrücke sind flexibler als Funktionsdeklarationen und werden oft für Funktionen verwendet, die nur in einem begrenzten Bereich benötigt werden, wie Callbacks oder Methodendefinitionen.
Mit ES6 (ECMAScript 2015) wurden Pfeilfunktionen (Arrow Functions) eingeführt, die eine kürzere Syntax für Funktionsausdrücke bieten:
// Grundlegende Form
const quadrieren = (zahl) => {
return zahl * zahl;
};
// Bei einem einzelnen Parameter können die Klammern weggelassen werden
const verdoppeln = zahl => {
return zahl * 2;
};
// Bei einem einzeiligen Funktionskörper mit direkter Rückgabe können die geschweiften Klammern und das return weggelassen werden
const halbieren = zahl => zahl / 2;
// Bei keinen Parametern sind leere Klammern erforderlich
const zufallszahl = () => Math.random();
// Bei Rückgabe eines Objektliterals in Kurzform sind runde Klammern nötig
const erstellePerson = name => ({ name, alter: 30 });Besonderheiten der Pfeilfunktionen:
this, sondern übernehmen das this aus
dem umgebenden (lexikalischen) Kontextconst counter = {
count: 0,
// Problematisch mit regulärer Funktion
incrementBad: function() {
setTimeout(function() {
console.log(this.count++); // NaN, da 'this' nicht counter ist
}, 1000);
},
// Korrekt mit Pfeilfunktion
incrementGood: function() {
setTimeout(() => {
console.log(this.count++); // 0, dann 1, 2, ...
}, 1000);
}
};new möglich)this benötigt wird)yield)Pfeilfunktionen eignen sich hervorragend für kurze Callbacks und
Funktionen, bei denen das umgebende this beibehalten werden
soll, sind aber nicht für alle Anwendungsfälle optimal.
ES6 führte eine verkürzte Syntax für Methoden in Objektliteralen ein:
// Vor ES6
const objekt1 = {
name: "Beispiel",
grüßen: function() {
return "Hallo, " + this.name;
}
};
// Ab ES6 - verkürzte Methodensyntax
const objekt2 = {
name: "Beispiel",
grüßen() {
return "Hallo, " + this.name;
}
};Diese Methoden verhalten sich wie reguläre Funktionen mit eigenem
this-Kontext, sind aber kürzer zu definieren.
Generatorfunktionen, eingeführt in ES6, ermöglichen es, Funktionen zu schreiben, die ihre Ausführung unterbrechen und später fortsetzen können:
function* sequenz() {
yield 1;
yield 2;
yield 3;
}
const generator = sequenz();
console.log(generator.next().value); // 1
console.log(generator.next().value); // 2
console.log(generator.next().value); // 3Generatorfunktionen werden durch das Sternchen (*)
gekennzeichnet und verwenden das yield-Keyword, um Werte
zurückzugeben. Sie sind besonders nützlich für die Arbeit mit Sequenzen
und asynchronen Abläufen und werden im Kapitel “Generatoren und
Iteratoren” ausführlicher behandelt.
Asynchrone Funktionen, eingeführt in ES2017, bieten eine elegante Syntax für die Arbeit mit Promises:
async function datenLaden() {
try {
const response = await fetch('https://api.beispiel.de/daten');
const daten = await response.json();
return daten;
} catch (error) {
console.error('Fehler beim Laden der Daten:', error);
}
}Asynchrone Funktionen werden mit dem async-Keyword
markiert und können das await-Keyword verwenden, um auf
Promise-Ergebnisse zu warten. Sie werden im Kapitel “Asynchrones
JavaScript” detaillierter behandelt.
JavaScript bietet vielfältige Möglichkeiten, mit Funktionsparametern umzugehen, von grundlegenden bis zu fortgeschrittenen Techniken.
In ihrer einfachsten Form deklarieren Funktionen benannte Parameter, die bei Aufruf mit Argumenten gefüllt werden:
function addieren(a, b) {
return a + b;
}
console.log(addieren(5, 3)); // 8JavaScript ist bezüglich Parametern flexibel:
undefinedarguments-Objekt zugänglich)function beispiel(a, b) {
console.log(a, b);
console.log("Alle Argumente:", arguments);
}
beispiel(1); // 1 undefined, Arguments: [1]
beispiel(1, 2, 3, 4); // 1 2, Arguments: [1, 2, 3, 4]In regulären Funktionen (nicht in Pfeilfunktionen) ist ein spezielles
arguments-Objekt verfügbar, das einem Array ähnelt und alle
übergebenen Argumente enthält:
function summe() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
console.log(summe(1, 2, 3, 4, 5)); // 15Das arguments-Objekt ist jedoch kein echtes Array und
besitzt nicht alle Array-Methoden. In modernem JavaScript werden daher
Rest-Parameter empfohlen.
Mit ES6 können Standardwerte für Parameter definiert werden, die
verwendet werden, wenn kein Argument übergeben wird oder
undefined übergeben wird:
function grüßen(name = "Gast", gruß = "Hallo") {
return `${gruß}, ${name}!`;
}
console.log(grüßen()); // "Hallo, Gast!"
console.log(grüßen("Max")); // "Hallo, Max!"
console.log(grüßen("Anna", "Hi")); // "Hi, Anna!"
console.log(grüßen(undefined, "Willkommen")); // "Willkommen, Gast!"Standardparameter werden nur aktiviert, wenn der Parameter
undefined ist - nicht bei null oder anderen
“falsy” Werten:
function config(options = {}, debug = false) {
console.log(options, debug);
}
config(null, 0); // null 0 (Standardwerte werden nicht verwendet)Standardparameter können auch Ausdrücke oder frühere Parameter referenzieren:
function bereichVerdoppeln(min = 0, max = min + 10) {
return [min, max];
}
console.log(bereichVerdoppeln()); // [0, 10]
console.log(bereichVerdoppeln(5)); // [5, 15]Rest-Parameter ermöglichen es, eine beliebige Anzahl von Argumenten als Array zu behandeln:
function summe(...zahlen) {
return zahlen.reduce((summe, zahl) => summe + zahl, 0);
}
console.log(summe(1, 2, 3)); // 6
console.log(summe(1, 2, 3, 4, 5)); // 15Rest-Parameter bieten gegenüber dem arguments-Objekt
mehrere Vorteile:
function formatieren(prefix, suffix, ...werte) {
return werte.map(wert => `${prefix}${wert}${suffix}`);
}
console.log(formatieren("<", ">", "a", "b", "c")); // ["<a>", "<b>", "<c>"]Rest-Parameter müssen der letzte Parameter in der Parameterliste sein.
Objekt- und Array-Destrukturierung kann direkt in der Parameterliste verwendet werden:
// Objektdestrukturierung
function anzeigenPerson({ name, alter = 'unbekannt', beruf = 'unbekannt' }) {
console.log(`Name: ${name}, Alter: ${alter}, Beruf: ${beruf}`);
}
anzeigenPerson({ name: "Max", alter: 30 }); // Name: Max, Alter: 30, Beruf: unbekannt
anzeigenPerson({ name: "Anna", beruf: "Entwicklerin" }); // Name: Anna, Alter: unbekannt, Beruf: Entwicklerin
// Array-Destrukturierung
function anzeigenKoordinaten([x, y, z = 0]) {
console.log(`X: ${x}, Y: ${y}, Z: ${z}`);
}
anzeigenKoordinaten([10, 20]); // X: 10, Y: 20, Z: 0Destrukturierung kann mit Standardwerten für den gesamten Parameter kombiniert werden:
function config({ port = 8080, timeout = 1000 } = {}) {
console.log(`Port: ${port}, Timeout: ${timeout}`);
}
config(); // Port: 8080, Timeout: 1000 (leeres Standardobjekt wird destrukturiert)
config({ port: 3000 }); // Port: 3000, Timeout: 1000 (fehlender Wert erhält Standard)Für die Arbeit mit Funktionen und Parametern haben sich einige Best Practices etabliert:
Wählen Sie die passende Funktionsart:
this-KontextSetzen Sie sinnvolle Standardparameter:
{} statt null)Begrenzen Sie die Anzahl der Parameter:
// Schlecht: Zu viele Parameter
function createUser(name, email, age, address, phone, isAdmin, language) {
// ...
}
// Besser: Optionen als Objekt
function createUser({ name, email, age, address, phone, isAdmin = false, language = 'en' } = {}) {
// ...
}Benennen Sie Parameter klar und verständlich:
Validieren Sie Parameter bei Bedarf:
function dividieren(a, b) {
if (typeof a !== 'number' || typeof b !== 'number') {
throw new TypeError('Parameter müssen Zahlen sein');
}
if (b === 0) {
throw new Error('Division durch Null nicht möglich');
}
return a / b;
}