Start · Sprachen · JavaScript · Kapitel · Funktionen & Closures
// Kapitel · JavaScript

Funktionen & Closures

Diese Sektion behandelt die Syntaxformen von Funktionen in JavaScript, also Deklaration, Ausdruck und Arrow Function, dazu Parameter-Features und Closures. Außerdem geht es um typische Fallstricke mit Gültigkeitsbereich und this.

Kurzantwort
Funktionen & Closures in JavaScript — kurz erklärt

Eine Funktion in JavaScript ist ein wiederverwendbarer Code-Block, der Parameter annimmt und optional einen Wert zurückgibt. JavaScript kennt drei Formen: Function-Declaration (function f(){}), Function-Expression (const f = function(){}) und Arrow-Function (const f = () => {}). Funktionen sind First-Class-Citizens — als Werte übergebbar.

In JavaScript sind Funktionen normale Werte. Du kannst sie Variablen zuweisen, als Argument übergeben und aus anderen Funktionen zurückgeben. Eine Closure entsteht, wenn eine Funktion Variablen aus dem Bereich verwendet, in dem sie definiert wurde. Diese Variablen bleiben erhalten, auch wenn die äußere Funktion schon beendet ist.

Deklaration, Ausdruck, Arrow Function

Funktionsdeklarationen werden gehoistet. Du kannst sie also schon vor ihrer Definition aufrufen. Bei Funktionsausdrücken und Arrow Functions geht das nicht. Arrow Functions haben außerdem kein eigenes this und kein arguments.

function add(a, b) { return a + b; }
const mul = function (a, b) { return a * b; };
const square = (x) => x * x;          // impliziter Rückgabewert
const toObj = (id) => ({ id });       // Objektliteral in Klammern!

Parameter: Defaults, Rest, Destrukturierung

Standardwerte greifen nur bei undefined, nicht bei null. Rest-Parameter sammeln die übrigen Argumente in einem echten Array.

const greet = (name = 'Welt', ...rest) =>
  `Hallo ${name}! (${rest.length} weitere)`;

const connect = ({ host = 'localhost', port = 80 } = {}) =>
  `${host}:${port}`;

connect({ port: 8080 }); // "localhost:8080"
connect();               // "localhost:80"

Closures

Die innere Funktion behält eine Referenz auf die Variablen der äußeren, keine Kopie. So lässt sich privater Zustand ohne Klassen umsetzen:

const createCounter = (start = 0) => {
  let count = start;
  return {
    inc: () => ++count,
    reset: () => { count = start; },
  };
};

const counter = createCounter();
counter.inc(); counter.inc(); // 2
// count ist von außen nicht erreichbar

Closures sind auch die Grundlage von Callbacks, Event-Handlern, Memoisierung und Currying.

Fallstricke

  • var in Schleifen: Alle Closures teilen sich dieselbe Variable. Mit let bekommt jeder Durchlauf eine eigene Bindung.
  • Arrow Functions als Methoden: this zeigt dann nicht auf das Objekt. Nutze dafür die Methodenkurzschreibweise obj = { run() { … } }.
  • Speicher: Closures halten referenzierte Objekte am Leben. Entferne Event-Listener, die du nicht mehr brauchst.
for (var i = 0; i < 3; i++) setTimeout(() => console.log(i)); // 3 3 3
for (let j = 0; j < 3; j++) setTimeout(() => console.log(j)); // 0 1 2

Häufige Fragen

Wann sollte ich Arrow-Functions vermeiden?

Immer wenn du eigenes this brauchst: Object-Methoden, Konstruktoren und prototype-Methoden. Arrow-Functions binden this lexikalisch aus dem umschließenden Scope.

Was ist Hoisting bei Funktionen?

Function-Declarations werden vollständig an den Anfang ihres Scopes gehoben — du kannst sie vor der Definition aufrufen. Function-Expressions und Arrow-Functions dagegen nicht: nur die Variable wird gehoben, der Wert nicht.

Wie definiere ich Default-Werte für Parameter?

Direkt in der Signatur: function f(x = 10, y = x * 2). Default-Werte werden nur ausgewertet, wenn das Argument undefined ist, nicht bei null oder 0.

Was ist ein Rest-Parameter?

Mit function f(...args) sammelst du beliebig viele Argumente in einem echten Array. Immer das letzte Parameter der Signatur. Ersetzt den veralteten arguments-Pseudo-Array.

Wie binde ich <code>this</code> explizit?

Drei Varianten: f.call(ctx, a, b), f.apply(ctx, [a,b]), const g = f.bind(ctx). bind gibt eine neue Funktion zurück — call/apply rufen sofort auf.