In JavaScript sind Funktionen First-Class Citizens — sie werden behandelt wie jeder andere Wert. Sie lassen sich in Variablen speichern, an Funktionen übergeben, von Funktionen zurückgeben, in Arrays oder Objects ablegen und zur Laufzeit erzeugen. Diese Eigenschaft macht Higher-Order Functions möglich (Funktionen, die Funktionen entgegennehmen oder zurückgeben), liefert das Fundament für Callback-Pattern und ermöglicht Function Composition. Dieser Artikel sammelt die Konsequenzen aus diesem einfachen Spec-Detail — und zeigt, wie es die meisten modernen JavaScript-Patterns trägt.

Funktion als Wert

Eine Funktion ist in JavaScript ein Object vom Typ function. Sie kann genauso wie jeder andere Wert behandelt werden.

JavaScript funktion-als-wert.js
// 1. In Variable speichern
const verdoppeln = function(x) { return x * 2; };
console.log(verdoppeln(5));

// 2. In Array
const mathFns = [
    x => x + 1,
    x => x * 2,
    x => x * x,
];
console.log(mathFns[2](4));   // 16

// 3. In Object
const ops = {
    add:    (a, b) => a + b,
    mul:    (a, b) => a * b,
    divide: (a, b) => a / b,
};
console.log(ops.mul(3, 4));   // 12

// 4. Properties an einer Funktion setzen
function gruss() { return 'Hi'; }
gruss.version = '1.0';
console.log(gruss.version);   // '1.0'

// 5. Vergleichen via Reference
const a = () => {};
const b = a;
console.log(a === b); // true (gleiche Reference)
Output
10
16
12
1.0
true

Jedes Verhalten, das man von Objekten kennt, gilt auch für Funktionen — sie sind eine Spezialform mit Aufrufbarkeit.

Higher-Order Functions

Eine Higher-Order Function ist eine Funktion, die mindestens eines der Folgenden tut:

  • nimmt eine Funktion als Argument entgegen
  • liefert eine Funktion als Rückgabewert

Beides sind direkte Konsequenzen aus First-Class-Status.

JavaScript higher-order.js
// Nimmt eine Funktion entgegen
function dreimal(fn) {
    fn();
    fn();
    fn();
}
dreimal(() => console.log('Tick'));

// Gibt eine Funktion zurück
function multipliziereMit(n) {
    return x => x * n;
}
const verdoppeln = multipliziereMit(2);
console.log(verdoppeln(5));   // 10

// Tut beides
function delay(fn, ms) {
    return (...args) => setTimeout(() => fn(...args), ms);
}
const verzoegert = delay(console.log, 100);
verzoegert('verzögert');
Output
Tick
Tick
Tick
10
verzögert

Higher-Order Functions sind das Rückgrat von Array-Methoden, Decorator-Pattern, React-Hooks, Middleware-Systemen, Observable-Libraries.

Built-in Higher-Order: Array-Methoden

Die wichtigste Sammlung von Higher-Order Functions in JavaScript: map, filter, reduce, forEach, find, some, every, flatMap. Alle nehmen eine Funktion als Argument.

JavaScript array-hof.js
const zahlen = [1, 2, 3, 4, 5, 6, 7, 8];

// map: Wert → Wert
const verdoppelt = zahlen.map(n => n * 2);

// filter: Wert → Boolean
const geraden = zahlen.filter(n => n % 2 === 0);

// reduce: aggregieren
const summe = zahlen.reduce((acc, n) => acc + n, 0);

// Kombiniert in Pipeline
const summeGeraderQuadrate = zahlen
    .filter(n => n % 2 === 0)
    .map(n => n * n)
    .reduce((acc, n) => acc + n, 0);

console.log({ verdoppelt, geraden, summe, summeGeraderQuadrate });
Output
{
  verdoppelt: [ 2, 4, 6, 8, 10, 12, 14, 16 ],
  geraden: [ 2, 4, 6, 8 ],
  summe: 36,
  summeGeraderQuadrate: 120
}

Diese Methoden sind die idiomatische Form moderner JavaScript-Programmierung — kompakt, deklarativ, ohne mutierenden State.

Callback-Pattern

Eine Funktion an eine andere übergeben, die sie zu einem bestimmten Zeitpunkt aufruft — Event-Handler, asynchrone APIs, Timer.

JavaScript callbacks.js
// Synchroner Callback
function reicheDurch(wert, callback) {
    return callback(wert);
}
console.log(reicheDurch(5, x => x * 10));

// Asynchroner Callback
function nachher(ms, callback) {
    setTimeout(callback, ms);
}
nachher(50, () => console.log('Fertig'));

// Klassische Node-Style: error-first callback
function ladeDaten(url, callback) {
    // Simuliert: liefert nach 30ms ein Ergebnis
    setTimeout(() => {
        if (!url) return callback(new Error('Keine URL'));
        callback(null, { ok: true, url });
    }, 30);
}

ladeDaten('http://example.com', (err, data) => {
    if (err) console.log('Fehler:', err.message);
    else console.log('Daten:', data);
});
Output
50
Fertig
Daten: { ok: true, url: 'http://example.com' }

Promises und async/await haben Callbacks in vielen Use-Cases ersetzt — Event-Handler, Stream-Listener, einfache Animationen sind aber weiterhin callback-basiert.

Function Composition

Eine größere Funktion aus kleineren bauen. Klassisch f(g(x)) oder mit compose/pipe deklarativer.

JavaScript composition.js
// Klein und benannt
const trimmen   = s => s.trim();
const klein     = s => s.toLowerCase();
const ohnePunkte = s => s.replace(/\./g, '');

// Direkt verschachtelt (lesbar von innen nach außen)
const verarbeiten = s => ohnePunkte(klein(trimmen(s)));
console.log(verarbeiten('  Hallo.WELT.  '));

// Mit pipe — lesbar von links nach rechts
const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x);
const sauber = pipe(trimmen, klein, ohnePunkte);
console.log(sauber('  Hallo.WELT.  '));
Output
hallowelt
hallowelt

Jede kleine Funktion ist isoliert testbar; Composition verbindet sie zu Pipelines. Das ist der Kern funktionalen Stils.

Decorator-Pattern — Wrappen mit Funktion-zurück

Eine Higher-Order Function, die eine vorhandene Funktion „dekoriert" — mit Logging, Caching, Authentifizierung, Timing.

JavaScript decorator.js
// Logging-Decorator
function logiere(fn) {
    return function(...args) {
        console.log('Aufruf:', fn.name, args);
        const result = fn(...args);
        console.log('Ergebnis:', result);
        return result;
    };
}

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

const summeMitLog = logiere(summe);
summeMitLog(2, 3);
Output
Aufruf: summe [ 2, 3 ]
Ergebnis: 5

Dieser Pattern ist die Grundlage hinter React-HOCs (Higher-Order Components), Redux-Middleware, Express-Middleware. Alles dasselbe Pattern, nur mit kontext-spezifischer Form.

Funktion zur Laufzeit erzeugen

Funktionen können auch dynamisch erzeugt werden — entweder über Closures (gewählt) oder über new Function() (selten, fast immer als Anti-Pattern).

JavaScript laufzeit-funktion.js
// Klassisch: Higher-Order-Factory
function erstelleAddierer(n) {
    return x => x + n;
}
const plus10 = erstelleAddierer(10);
console.log(plus10(5));

// Selten: new Function (kein Lexical Scope, langsamer, eval-ähnlich)
const f = new Function('a', 'b', 'return a + b;');
console.log(f(2, 3));
Output
15
5

new Function() ist vom Strict-Mode ausgenommen, hat keinen Zugriff auf den lexikalischen Scope und wird bei jeder Erstellung neu kompiliert — typisches Anti-Pattern. Closures sind in 99% der Fälle die saubere Lösung.

Strategie-Pattern — Funktionen als Konfiguration

Eine Funktion als Konfigurations-Wert zu übergeben ist eine elegante Form, Verhalten zu parametrisieren.

JavaScript strategie.js
function sortiere(arr, vergleiche) {
    return [...arr].sort(vergleiche);
}

const zahlen = [10, 1, 5, 3, 8];

// Aufsteigend
console.log(sortiere(zahlen, (a, b) => a - b));

// Absteigend
console.log(sortiere(zahlen, (a, b) => b - a));

const namen = ['Anna', 'bob', 'Chris'];
// Case-insensitive
console.log(sortiere(namen, (a, b) =>
    a.toLowerCase().localeCompare(b.toLowerCase())
));
Output
[ 1, 3, 5, 8, 10 ]
[ 10, 8, 5, 3, 1 ]
[ 'Anna', 'bob', 'Chris' ]

Array.prototype.sort ist ein lehrreiches Beispiel: dieselbe Funktion sortiert in jeder gewünschten Reihenfolge — die Strategie kommt von außen, als Vergleichs-Funktion.

Event-Listener — Funktionen als Subscribers

Ein klassischer Anwendungsfall: ein Object hält eine Liste von Funktionen, die bei bestimmten Ereignissen aufgerufen werden.

JavaScript event-emitter.js
function erstelleEmitter() {
    const listeners = new Map();

    return {
        on(event, fn) {
            if (!listeners.has(event)) listeners.set(event, []);
            listeners.get(event).push(fn);
        },
        emit(event, ...args) {
            (listeners.get(event) || []).forEach(fn => fn(...args));
        },
    };
}

const bus = erstelleEmitter();

bus.on('user', user => console.log('User-Event:', user));
bus.on('user', user => console.log('Logged:', user.name));

bus.emit('user', { name: 'Anna', alter: 30 });
Output
User-Event: { name: 'Anna', alter: 30 }
Logged: Anna

Dasselbe Pattern findet sich in DOM-Events (addEventListener), Node's EventEmitter, RxJS-Observables. Alles möglich, weil Funktionen First-Class sind.

Interessantes

First-Class ist Spec-Eigenschaft, nicht Library-Feature

Es gibt keinen function-Typ-Wrapper oder ähnliches — JavaScript-Funktionen SIND von der Sprache her Objekte mit Aufrufbarkeit. Daher funktioniert fn.foo = 'bar', typeof fn === 'function', und Funktionen können in jeder Collection liegen.

typeof unterscheidet Funktion von Object

Obwohl Funktionen Objekte sind, liefert typeof fn === 'function' — eine Sonder-Regel im typeof-Algorithmus. typeof {} === 'object'. Das ist die einzige Stelle, an der die Sprache zwischen den beiden in einem typeof-Check unterscheidet.

Function-Properties: name, length und beliebige eigene Felder

fn.name, fn.length sind eingebaute Properties. Eigene Properties kann man problemlos setzen. Manche Libraries nutzen das, um Metadaten an Funktionen zu hängen — etwa fn.__cached als Memoization-Marker.

Higher-Order Functions sind in JS Standard, nicht Spezialfall

Anders als in C oder Java, wo Function-Pointers/Functional-Interfaces ein Sonder-Konstrukt sind, ist eine Higher-Order Function in JavaScript die Norm. Array.map, addEventListener, setTimeout, Promise.then — überall.

Composition statt Vererbung — funktionales Idiom

In OO-Sprachen löst man Wiederverwendung typischerweise mit Klassen-Hierarchie. In FP-Stil mit Function Composition: kleine Funktionen, die sich zu größeren zusammenstellen. pipe(a, b, c) statt class C extends B extends A.

Callback-Hell führte zu Promises — und schließlich async/await

Tief verschachtelte Callbacks ('Pyramid of Doom') waren in Pre-Promise-Code ein realer Schmerz. Promises kamen mit ES2015, async/await mit ES2017 — beide sind Verbesserungen, aber Callbacks sind keineswegs „falsch". Für synchrone Higher-Order-Funktionen (map, filter) gibt es ohnehin keine Promises.

React Hooks sind reine Higher-Order-Function-Pattern

useState, useEffect, useMemo — alle sind Funktionen, die Funktionen als Argument nehmen und State/Side-Effects via Closures verwalten. React funktioniert nur, weil JavaScript First-Class Functions hat.

Function-Identität: jeder neue Wert ist eine eigene Funktion

const a = () => 1; const b = () => 1;a !== b, auch wenn beide identischen Body haben. In React mit useEffect/useMemo führt das oft zu unnötigen Re-Renders, wenn man bei jedem Render eine neue Function-Reference erzeugt. Lösung: useCallback oder die Funktion außerhalb der Component definieren.

Weiterführende Ressourcen

Externe Quellen

/ Weiter

Zurück zu Funktionen

Zur Übersicht