Strukturiere deinen Code mit Currying, Funktionskomposition und unveränderlichen Daten, um Vorhersehbarkeit und Testbarkeit zu gewinnen.
Diese Lektion in Kodokon öffnenJavaScript behandelt Funktionen als First-Class-Werte, was die Tür zu funktionalen Mustern öffnet. Currying verwandelt eine Funktion mit n Argumenten in eine Kette von Funktionen mit einem einzigen Argument: f(a, b, c) wird zu f(a)(b)(c). Nicht zu verwechseln mit der partiellen Anwendung, die einige Argumente in einem einzigen Schritt festlegt (fn.bind(null, a)). Currying glänzt darin, aus generischen Funktionen spezialisierte zu erzeugen.
const curry = (fn) => {
const arity = fn.length;
return function curried(...args) {
if (args.length >= arity) return fn(...args);
return (...rest) => curried(...args, ...rest);
};
};
const add3 = (a, b, c) => a + b + c;
const addCurried = curry(add3);
console.log(addCurried(1)(2)(3)); // 6
console.log(addCurried(1, 2)(3)); // 6Eine Feinheit der Spezifikation: fn.length zählt nur die Parameter, die vor dem ersten Default- oder Rest-Parameter stehen. (a, b = 1) => {} hat eine length von 1, (...args) => {} von 0. Einem aritätsbasierten curry muss man daher Funktionen mit einfachen Parametern geben. Komposition ist der nächste Schritt: kleine reine Funktionen zu lesbaren Pipelines zusammenzufügen.
const pipe = (...fns) => (input) =>
fns.reduce((acc, fn) => fn(acc), input);
const trim = (s) => s.trim();
const lower = (s) => s.toLowerCase();
const dashes = (s) => s.replace(/\s+/g, "-");
const toSlug = pipe(trim, lower, dashes);
console.log(toSlug(" Hello World "));
// "hello-world"pipe(f, g, h)(x) berechnet h(g(f(x))): Du liest es in Ausführungsreihenfolge. Die Variante compose wendet von rechts nach links an, wie in der mathematischen Notation. Diese Pipelines sind nur wertvoll, wenn die Funktionen rein sind - keine Seiteneffekte, keine versteckten Abhängigkeiten -, was unveränderliche Daten erfordert: Statt ein Objekt zu mutieren, erzeugst du eine neue Version davon, und Referenzgleichheit genügt dann, um eine Änderung zu erkennen (das Herzstück von Reacts Reconciliation).
const state = Object.freeze({
user: { name: "Ada" },
tags: ["js"]
});
const next = {
...state,
tags: [...state.tags, "fp"]
};
const deepCopy = structuredClone(state);
deepCopy.user.name = "Grace"; // independent copybind, Currying nur mit Arrow-Funktionenpipe(f, g, h)(x) gleichwertig?const s = Object.freeze({ a: { b: 1 } }) die Zuweisung s.a.b = 2?s.a ist nicht eingefroren