Funktionen

Geschätzte Lektüre: 13 Minuten 386 Ansichten

Funktionen bilden das Herzstück der JavaScript-Programmierung und sind unverzichtbare Bausteine für strukturierten, wiederverwendbaren und effizienten Code.

Grundlegende Konzepte von Funktionen

Eine Funktion ist im Wesentlichen ein abgeschlossener Codeblock, der eine bestimmte Aufgabe erfüllt und bei Bedarf immer wieder aufgerufen werden kann. Stellen Sie sich eine Funktion wie eine kleine Fabrik vor: Sie nimmt Rohmaterial entgegen (Eingabeparameter), verarbeitet es nach einem festgelegten Verfahren (Funktionskörper) und liefert ein fertiges Produkt (Rückgabewert) aus.

Die einfachste Form einer Funktion in JavaScript ist die Funktionsdeklaration:

function begruessung() {
  console.log("Guten Tag!");
}

Diese Funktion mit dem Namen begruessung gibt bei Aufruf einfach einen Gruß in der Konsole aus. Der Aufruf erfolgt durch begruessung() .Der große Vorteil: Diesen Codeblock können wir nun beliebig oft verwenden, ohne ihn jedes Mal neu schreiben zu müssen.

Parameter und Argumente

Funktionen werden besonders mächtig, wenn wir ihnen Daten zur Verarbeitung übergeben können. Hier kommen Parameter ins Spiel – Platzhalter, die Werte bei Aufruf entgegennehmen:

function quadrat(zahl) {
  return zahl * zahl;
}

In diesem Beispiel ist zahl der Parameter. Beim Aufruf quadrat(5) ist 5 das sogenannte Argument – der konkrete Wert, der für den Parameter eingesetzt wird. Der return Befehl gibt das Ergebnis zurück, das wir dann weiterverwenden können:

let ergebnis = quadrat(5); // ergebnis ist jetzt 25

Funktionen können auch mehrere Parameter entgegennehmen:

function multipliziere(a, b) {
  return a * b;
}

console.log(multipliziere(3, 4)); // Ausgabe: 12

Verschiedene Arten von Funktionen

JavaScript bietet mehrere Wege, Funktionen zu definieren, die sich in Syntax und Verhalten unterscheiden.

Funktionsdeklaration

Die klassische Form, die wir bereits gesehen haben:

function summe(a, b) {
  return a + b;
}

Besonderheit: Funktionsdeklarationen werden gehoisted, das heißt sie stehen im gesamten umgebenden Scope zur Verfügung, auch wenn sie erst später im Code definiert werden.

Funktionsausdruck

Hier wird die Funktion einer Variable zugewiesen:

const summe = function(a, b) {
  return a + b;
};

Diese Form wird nicht gehoisted und ist erst nach ihrer Zuweisung verfügbar.

Arrow-Funktionen (Pfeilfunktionen)

Eingeführt mit ES6, bieten sie eine kompakte Syntax:

const summe = (a, b) => {
  return a + b;
};

Oder noch kürzer bei einfachen Ausdrücken:

const summe = (a, b) => a + b;

Arrow-Funktionen haben zudem ein spezielles Verhalten mit dem this Schlüsselwort, worauf wir später eingehen.

Methoden

Funktionen innerhalb von Objekten nennt man Methoden:

const rechner = {
  addieren: function(a, b) {
    return a + b;
  }
};

// Alternative ES6-Syntax:
const rechner = {
  addieren(a, b) {
    return a + b;
  }
};

Rückgabewerte und die return-Anweisung

Die return Anweisung beendet die Funktion und gibt einen Wert zurück. Ohne explizites return gibt die Funktion undefined zurück:

function ohneReturn() {
  // tut etwas ohne Rückgabe
}
console.log(ohneReturn()); // undefined

Interessant ist, dass return die Funktion sofort beendet – Code nach dem return wird nicht mehr ausgeführt:

function fruchtCheck(frucht) {
  if (!frucht) return "Keine Frucht angegeben";
  return `Ihre Frucht ist: ${frucht}`;
}

Funktionsparameter und Standardwerte

In ES6 wurden Standardparameter eingeführt, die verwendet werden, wenn kein Argument übergeben wird:

function begruesse(name = "Gast") {
  console.log(`Hallo, ${name}!`);
}

begruesse(); // Hallo, Gast!
begruesse("Anna"); // Hallo, Anna!

Man kann auch komplexere Standardwerte setzen:

function erstelleUser(name, details = { admin: false, aktiv: true }) {
  console.log(name, details);
}

Rest-Parameter und Spread-Operator

Der Rest-Parameter () erlaubt es, eine unbestimmte Anzahl von Argumenten als Array zu erfassen:

function summeAlle(...zahlen) {
  return zahlen.reduce((sum, num) => sum + num, 0);
}

console.log(summeAlle(1, 2, 3, 4)); // 10

Der Spread-Operator sieht ähnlich aus, hat aber die entgegengesetzte Funktion – er „entpackt“ ein Array in einzelne Argumente:

const zahlen = [1, 2, 3];
console.log(summeAlle(...zahlen)); // 6

Scope, Closures und Hoisting

Funktionen schaffen ihren eigenen Scope – einen Bereich, in dem Variablen existieren. Variablen, die innerhalb einer Funktion deklariert werden, sind außerhalb nicht sichtbar (lokale Variablen). Umgekehrt kann eine Funktion auf Variablen ihres äußeren Scopes zugreifen.

Eine besonders interessante Konsequenz davon sind Closures – Funktionen, die sich „ihre Umgebung merken“:

function erstelleZaehler() {
  let count = 0;
  return function() {
    count++;
    return count;
  };
}

const zaehler = erstelleZaehler();
console.log(zaehler()); // 1
console.log(zaehler()); // 2

Die innere Funktion behält Zugriff auf count auch nachdem erstelleZaehler bereits abgeschlossen ist.

Hoisting
Funktionsdeklarationen werden an den Anfang des Scopes „gehoben“ und sind vor ihrer Definition nutzbar.

sayHello(); // Funktioniert wegen Hoisting

function sayHello() {
  console.log("Hallo!");
}

Achtung: Bei Funktionsausdrücken (z. B. mit const) gibt es kein Hoisting!

Scope
Definiert den Sichtbarkeitsbereich von Variablen.
Lokale Variablen sind nur innerhalb der Funktion sichtbar.
Globale Variablen sind überall sichtbar.

let global = "Ich bin global";

function checkScope() {
  let local = "Ich bin lokal";
  console.log(global); // Zugriff möglich
}

console.log(local); // Fehler: "local" ist hier nicht definiert

Closure
Eine Funktion, die sich „erinnert“, in welchem Scope sie erstellt wurde, und auf Variablen aus diesem Scope zugreifen kann – selbst nachdem der äußere Scope beendet wurde.

function outer() {
  let outerVar = "Ich bin außen!";

  function inner() {
    console.log(outerVar); // Greift auf "outerVar" zu
  }

  return inner;
}

const closureFunc = outer();
closureFunc(); // Loggt: "Ich bin außen!"

Wichtig: Die inner-Funktion behält Zugriff auf outerVar, auch nachdem outer bereits beendet wurde.

Hoisting: Funktionsdeklarationen sind vor ihrer Definition aufrufbar.
• Scope: Bestimmt, wo Variablen sichtbar sind.
• Closure: Funktionen „merken“ sich ihren Entstehungs-Scope.

Rekursion

Eine Funktion kann sich selbst aufrufen – man nennt dies Rekursion. Dies ist besonders für Probleme geeignet, die sich in kleinere, ähnliche Teilprobleme zerlegen lassen:

function fakultaet(n) {
  if (n <= 1) return 1;
  return n * fakultaet(n - 1);
}

console.log(fakultaet(5)); // 120 (5! = 5*4*3*2*1 = 120)

Wichtig ist immer eine Abbruchbedingung (hier n <= 1 ), sonst entsteht eine Endlosschleife.

Callback-Funktionen

Funktionen können anderen Funktionen als Argumente übergeben werden – solche Funktionen nennt man Callbacks:

function begruesse(name) {
  console.log(`Hallo, ${name}!`);
}

function benutzerAktion(callback) {
  const name = prompt("Wie heißt du?");
  callback(name);
}

benutzerAktion(begruesse);

Callbacks sind fundamental für asynchrone Operationen in JavaScript, etwa bei Event-Handlern oder AJAX-Anfragen.

Higher-Order Functions

Funktionen, die andere Funktionen als Argumente empfangen oder Funktionen zurückgeben, nennt man Higher-Order Functions. JavaScripts Array-Methoden sind gute Beispiele:

const zahlen = [1, 2, 3, 4];
const quadrate = zahlen.map(num => num * num);
// quadrate ist jetzt [1, 4, 9, 16]

Hier ist map eine Higher-Order Function, die unsere Arrow-Funktion auf jedes Element anwendet.

IIFE (Immediately Invoked Function Expression)

Eine IIFE ist eine Funktion, die sofort nach ihrer Definition ausgeführt wird:

Dieses Muster war früher besonders wichtig, um einen eigenen Scope zu schaffen (vor der Einführung von Block-Scopes mit let/const ).

this in Funktionen

Das this Keyword in JavaScript verweist auf das Objekt, im Kontext dessen eine Funktion aufgerufen wird. Das Verhalten von this ist oft verwirrend:

const person = {
  name: "Max",
  sagHallo: function() {
    console.log(`Hallo, ich bin ${this.name}`);
  }
};

person.sagHallo(); // "Hallo, ich bin Max"

Aber Vorsicht bei Callbacks:

setTimeout(person.sagHallo, 1000); // "Hallo, ich bin undefined"

Hier geht der Kontext verloren. Abhilfe schafft bind :

setTimeout(person.sagHallo.bind(person), 1000);

Arrow-Funktionen verhalten sich anders – sie erben this aus dem umgebenden Scope:

const person = {
  name: "Max",
  sagHallo: () => {
    console.log(`Hallo, ich bin ${this.name}`);
  }
};

person.sagHallo();
// "Hallo, ich bin undefined" (weil this nicht auf person verweist)

Funktionen als Objekte

In JavaScript sind Funktionen spezielle Objekte. Das bedeutet, sie können Eigenschaften haben:

function sagenHallo() {
  console.log(sagenHallo.text);
}

sagenHallo.text = "Hallo Welt!";
sagenHallo(); // "Hallo Welt!"

Currying

Currying ist eine Technik, bei der eine Funktion mit mehreren Argumenten in eine Folge von Funktionen umgewandelt wird, die jeweils ein einzelnes Argument entgegennehmen:

function addieren(a) {
  return function(b) {
    return a + b;
  };
}

const addiere5 = addieren(5);
console.log(addiere5(3)); // 8

Mit Arrow-Funktionen sieht das eleganter aus:

const addieren = a => b => a + b;

Memoization

Dies ist eine Optimierungstechnik, bei der teure Funktionsaufrufe zwischengespeichert werden:

function memoize(fn) {
  const cache = {};
  return function(...args) {
    const key = JSON.stringify(args);
    if (cache[key]) return cache[key];
    const result = fn(...args);
    cache[key] = result;
    return result;
  };
}

const fakultaet = memoize(n => {
  if (n <= 1) return 1;
  return n * fakultaet(n - 1);
});

Generatoren

Generatoren sind spezielle Funktionen, die ihren Verlauf anhalten und später fortsetzen können:

function* zahlenGenerator() {
  let zahl = 1;
  while (true) {
    yield zahl++;
  }
}

const generator = zahlenGenerator();
console.log(generator.next().value); // 1
console.log(generator.next().value); // 2

Asynchrone Funktionen (async/await)

Moderne JavaScript bietet eine elegante Syntax für asynchrone Operationen:

async function datenLaden() {
  try {
    const antwort = await fetch('https://api.example.com/data');
    const daten = await antwort.json();
    console.log(daten);
  } catch (fehler) {
    console.error('Fehler beim Laden:', fehler);
  }
}

Vielseitig und mächtig

Funktionen in JavaScript sind äußerst vielseitig und mächtig. Von einfachen Code-Wiederverwendungen bis hin zu komplexen Mustern wie Closures, Currying oder Generatoren bilden sie die Grundlage für saubere, modulare und effiziente Programmierung. Das Verständnis der verschiedenen Funktionskonzepte und -techniken ist essentiell für jeden JavaScript-Entwickler, der professionellen, wartbaren Code schreiben möchte.

Die Kunst besteht darin, für jede Aufgabe die passende Funktionsart und das richtige Muster zu wählen – ob einfache Funktionsdeklaration, Arrow-Funktion, Methode, Generator oder asynchrone Funktion. Mit diesem umfassenden Wissen sind Sie nun bestens gerüstet, um JavaScript-Funktionen in all ihren Facetten effektiv einzusetzen.

Dieses Dokument teilen

Funktionen

Oder Link kopieren

INHALT

Abonnieren

×
Cancel