Structurez votre code avec le currying, la composition de fonctions et des données immuables pour gagner en prévisibilité et en testabilité.
Ouvrir cette leçon dans KodokonJavaScript traite les fonctions comme des valeurs de première classe, ce qui ouvre la voie aux patterns fonctionnels. Le currying transforme une fonction à n arguments en une chaîne de fonctions à un argument : f(a, b, c) devient f(a)(b)(c). À ne pas confondre avec l'application partielle, qui fixe certains arguments en une seule fois (fn.bind(null, a)). Le currying brille pour créer des fonctions spécialisées à partir de fonctions génériques.
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)); // 6Subtilité de spécification : fn.length ne compte que les paramètres situés avant le premier paramètre par défaut ou rest. (a, b = 1) => {} a une length de 1, (...args) => {} de 0. Un curry fondé sur l'arité doit donc recevoir des fonctions aux paramètres simples. La composition est l'étape suivante : assembler des petites fonctions pures en pipelines lisibles.
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) calcule h(g(f(x))) : lecture dans l'ordre d'exécution. La variante compose applique de droite à gauche, comme la notation mathématique. Ces pipelines n'ont de valeur que si les fonctions sont pures - sans effet de bord ni dépendance cachée - ce qui suppose des données immuables : au lieu de modifier un objet, vous en produisez une nouvelle version, et l'égalité de référence suffit alors à détecter un changement (le cœur de la réconciliation de React).
const state = Object.freeze({
user: { name: "Ada" },
tags: ["js"]
});
const next = {
...state,
tags: [...state.tags, "fp"]
};
const deepCopy = structuredClone(state);
deepCopy.user.name = "Grace"; // copie independantebind, le currying qu'avec les fléchéespipe(f, g, h)(x) ?const s = Object.freeze({ a: { b: 1 } }), l'affectation s.a.b = 2 fonctionne-t-elle ?s.a n'est pas gelé