Zum Inhalt springen

JavaScript-Currying und partielle Anwendung

Currying und partielle Anwendung sind leistungsstarke funktionale Programmiertechniken, die die Modularität und Wiederverwendbarkeit Ihres JavaScript-Codes erheblich verbessern können. In diesem Artikel tauchen wir tief in diese Konzepte ein, untersuchen bewährte Vorgehensweisen und geben praktische Beispiele, die Ihnen helfen, ihre Verwendung zu meistern.

Currying verstehen

Currying ist eine Technik, bei der eine Funktion in eine Folge von Funktionen umgewandelt wird, von denen jede genau ein Argument entgegennimmt. Dadurch können Sie eine Funktion mit mehreren Argumenten in eine Reihe von unären Funktionen (Funktionen mit einem Argument) aufteilen.

Beispiel für Currying

Betrachten Sie eine einfache Funktion, die drei Zahlen addiert:


javascript
function add(a, b, c) {
    return a + b + c;
}

Wir können diese Funktion in eine gecurryte Version umwandeln:


Output appears here after Run.

Erklärung:

  • Die Funktion add nimmt drei Argumente entgegen und gibt ihre Summe zurück.
  • Die Funktion curryAdd ist eine gecurryte Version von add. Sie nimmt ein Argument a entgegen und gibt eine weitere Funktion zurück, die b entgegennimmt. Diese zweite Funktion gibt wiederum eine weitere Funktion zurück, die c entgegennimmt. Die innerste Funktion gibt die Summe von a, b und c zurück.

Vorteile von Currying

  1. Wiederverwendbarkeit: Gecurryte Funktionen ermöglichen es Ihnen, neue Funktionen zu erstellen, indem Sie einige Argumente fest vorgeben. Das erhöht die Wiederverwendbarkeit, da Sie leicht spezialisierte Versionen einer Funktion erstellen können, ohne Code zu duplizieren.

Output appears here after Run.

Hier ist curriedAdd eine gecurryte Version der Funktion add. Sie ermöglicht es uns, spezialisierte Funktionen wie add5 zu erstellen, indem wir das erste Argument (a) auf 5 festlegen. Das fördert die Wiederverwendung von Code, da wir mehrere spezialisierte Funktionen erstellen können, ohne die Logik für die Addition zu wiederholen.

  1. Funktionskomposition: Currying erleichtert das Zusammensetzen von Funktionen. Funktionskomposition ist der Prozess, zwei oder mehr Funktionen zu kombinieren, um eine neue Funktion zu erzeugen.

Output appears here after Run.

In diesem Beispiel kombinieren wir die Funktionen multiply und addOne mithilfe von Currying. Durch das Currying dieser Funktionen können wir leicht eine neue Funktion addOneThenMultiplyBy5 erstellen, die zuerst 1 zum Eingabewert (x) addiert und dann das Ergebnis mit 5 multipliziert. Dies zeigt, wie Currying die Funktionskomposition erleichtert und es einfacher macht, neue Funktionen durch die Kombination bestehender Funktionen zu erstellen.

Currying in JavaScript implementieren

Wir können eine Hilfsfunktion erstellen, um jede Funktion zu curryen. Hier ist eine Implementierung einer generischen Currying-Funktion:


Output appears here after Run.

Erklärung:

  1. Currying-Funktion (curry):

    • Die Funktion curry nimmt eine andere Funktion fn als Eingabe.
    • Sie gibt eine neue Funktion namens curried zurück.
    • Diese Funktion curried nimmt mithilfe der Rest-Parameter-Syntax (...args) beliebig viele Argumente entgegen.
  2. Gecurryte Funktion (curried):

    • Innerhalb von curried wird geprüft, ob die Anzahl der übergebenen Argumente (args.length) größer oder gleich der Anzahl der von der ursprünglichen Funktion fn erwarteten Argumente (fn.length) ist.
    • Wenn genügend Argumente vorhanden sind, ruft sie die ursprüngliche Funktion fn mit diesen Argumenten über fn.apply(this, args) auf.
    • Wenn nicht genügend Argumente vorhanden sind, gibt sie eine neue Funktion zurück, die weitere Argumente (nextArgs) mithilfe des Spread-Operators (...nextArgs) akzeptiert.
    • Diese neue Funktion rekursiv ruft curried mit den kombinierten Argumenten (args.concat(nextArgs)) auf und stellt so sicher, dass alle Argumente schließlich gesammelt werden, bevor die ursprüngliche Funktion fn aufgerufen wird.

    Hinweis: fn.length zählt nur Parameter ohne Standardwerte und ignoriert Rest-Parameter.

  3. Beispielverwendung:

    • Wir definieren eine Funktion multiply, die drei Argumente entgegennimmt und ihr Produkt zurückgibt.
    • Wir erstellen eine gecurryte Version der Funktion multiply, indem wir sie an die Funktion curry übergeben, die eine neue Funktion curriedMultiply zurückgibt.
    • Jetzt kann curriedMultiply mit einem, zwei oder drei Argumenten aufgerufen werden.
    • Jedes Mal, wenn wir curriedMultiply mit einem Argument oder mehreren Argumenten aufrufen, gibt sie eine neue Funktion zurück, bis alle Argumente gesammelt sind; danach gibt sie das Ergebnis der Multiplikation der Argumente zurück.

Partielle Anwendung erkunden

Partielle Anwendung ist eine Technik, bei der Sie eine neue Funktion erstellen, indem Sie einige Argumente der ursprünglichen Funktion vorab belegen. Das ist besonders nützlich, um spezialisierte Funktionen zu erstellen.

Beispiel für partielle Anwendung

Betrachten Sie die folgende Funktion, die eine Nachricht formatiert:


javascript
function formatMessage(greeting, name) {
    return `${greeting}, ${name}!`;
}

Wir können eine partiell angewendete Funktion erstellen:


Output appears here after Run.

Erklärung:

  • Die Funktion formatMessage nimmt zwei Argumente, greeting und name, entgegen und gibt eine formatierte Nachricht zurück.
  • Die Funktion partial nimmt eine Funktion fn und einige vorab festgelegte Argumente (...presetArgs) entgegen. Sie gibt eine neue Funktion zurück, die die verbleibenden Argumente (...laterArgs) entgegennimmt.
  • Wenn die neue Funktion aufgerufen wird, kombiniert sie presetArgs und laterArgs und ruft die ursprüngliche Funktion fn mit diesen Argumenten auf.
  • Mit partial erstellen wir greetHello, eine Funktion, die immer "Hello" als Begrüßung verwendet. Wenn sie mit einem Namen aufgerufen wird, gibt sie die vollständige Nachricht zurück.

Vorteile der partiellen Anwendung

  1. Vereinfachung: Einfachere Funktionen aus komplexeren erstellen

    Angenommen, wir haben eine Funktion, die den Endpreis eines Artikels nach Rabatt und Steuer berechnet.


javascript
function calculateFinalPrice(price, discount, tax) {
    return price - (price * discount) + (price * tax);
}

Diese Funktion benötigt drei Argumente, was die wiederholte Verwendung etwas umständlich macht, wenn Rabatt- und Steuersätze oft gleich sind. Mit partieller Anwendung können wir das vereinfachen.


Output appears here after Run.

Im obigen Beispiel ist applyDiscountAndTax eine partiell angewendete Funktion, die die Werte für discount und tax vorab festlegt. Dadurch lässt sich der Endpreis für verschiedene Artikel leichter berechnen, ohne die Rabatt- und Steuersätze jedes Mal erneut angeben zu müssen.

  1. Code-Wiederverwendbarkeit: Häufige Funktionslogik mit unterschiedlichen vorab festgelegten Argumenten wiederverwenden

    Stellen Sie sich vor, wir haben eine Funktion, die Nachrichten mit unterschiedlichen Schweregraden protokolliert.


javascript
function logMessage(level, message) {
    console.log(`[${level}] ${message}`);
}

Wir können mithilfe partieller Anwendung wiederverwendbare Funktionen für verschiedene Protokollstufen erstellen.


Output appears here after Run.

Hier ist createLogger eine partiell angewendete Funktion, die das Argument level festlegt. Die Funktionen infoLogger und errorLogger können nun verwendet werden, um Nachrichten mit den vorab festgelegten Protokollstufen zu protokollieren und dabei die gemeinsame Logik von logMessage wiederzuverwenden.

  1. Bessere Lesbarkeit: Macht Code lesbarer, indem komplexe Funktionen aufgeteilt werden Betrachten Sie eine Funktion, die Datumsangaben in verschiedenen Stilen formatiert.

javascript
function formatDate(date, format) {
    const options = { year: 'numeric', month: '2-digit', day: '2-digit' };
    if (format === 'US') {
        options.month = 'long';
    } else if (format === 'EU') {
        options.day = 'numeric';
        options.month = 'numeric';
    }
    return new Date(date).toLocaleDateString(undefined, options);
}

Durch partielle Anwendung können wir lesbarere Funktionen für verschiedene Datumsformate erstellen.


Output appears here after Run.

createDateFormatter wendet das Argument format partiell an und erzeugt dadurch spezifische Funktionen für US- und EU-Datumsformate. Diese Aufteilung macht den Code lesbarer und leichter verständlich, da jeder Formatter-Funktion ein bestimmtes Format zugeordnet ist.

Diese Beispiele zeigen, wie partielle Anwendung in JavaScript komplexe Funktionen vereinfachen, die Wiederverwendbarkeit des Codes erhöhen und die Lesbarkeit verbessern kann, wodurch der Code leichter zu verwalten und zu verstehen ist.

Best Practices für die Verwendung von Currying und partieller Anwendung

Funktionen rein halten

  • Stellen Sie sicher, dass gecurryte und partiell angewendete Funktionen rein bleiben, also ohne Seiteneffekte. Das macht sie leichter nachvollziehbar und testbar.

Nur bei Bedarf einsetzen

  • Verwenden Sie Currying und partielle Anwendung dann, wenn sie natürlich zum jeweiligen Problem passen.
  • Vermeiden Sie den übermäßigen Einsatz dieser Techniken, da sie den Code schwerer verständlich machen können, wenn sie nicht mit Bedacht verwendet werden.

Funktionskomposition nutzen

  • Kombinieren Sie gecurryte Funktionen, um komplexere Funktionalität zu erstellen. Currying funktioniert gut mit Funktionskomposition und führt zu modularerem Code.

Dokumentation und Benennung

  • Dokumentieren Sie gecurryte und partiell angewendete Funktionen sorgfältig, um ihre erwartete Verwendung zu verdeutlichen.
  • Verwenden Sie klare und aussagekräftige Namen für Funktionen, um ihren Zweck zu vermitteln.

INFO

Wenn Sie Currying und partielle Anwendung häufig verwenden, sollten Sie die Bibliothek Lodash in Betracht ziehen, die praktische Hilfsfunktionen wie _.curry und _.partial bereitstellt.

Mit Array-Methoden kombinieren

Currying lässt sich effektiv mit Array-Methoden wie map, filter und reduce kombinieren, um prägnanten und ausdrucksstarken Code zu schreiben.


Output appears here after Run.

Erklärung:

  • Die Funktion curriedMultiply wird verwendet, um multiplyByTwo zu erstellen, eine Funktion, die ihr Argument mit 2 multipliziert.
  • Das Array numbers wird mit map transformiert, wobei multiplyByTwo auf jedes Element angewendet wird, wodurch ein neues Array mit verdoppelten Zahlen entsteht.

Fazit

Currying und partielle Anwendung in JavaScript bieten leistungsstarke Techniken, um die Funktionskomposition zu vereinfachen, die Wiederverwendbarkeit des Codes zu erhöhen und die Lesbarkeit zu verbessern. Currying wandelt Funktionen mit mehreren Argumenten in eine Folge von Funktionen mit einem Argument um und ermöglicht so flexibleren und modulareren Code. Partielle Anwendung erlaubt es, Funktionsargumente vorab festzulegen, was die Wiederverwendung von Code und die Vereinfachung komplexer Funktionen erleichtert. Durch den Einsatz dieser funktionalen Programmierkonzepte können Entwickler saubereren, prägnanteren und besser wartbaren JavaScript-Code schreiben.

Practice

What is correct about Currying in JavaScript?

Finden Sie das nützlich?

Dual-run-Vorschau — vergleichen Sie mit den Symfony-Routen live.