W3docs

Curryfication et application partielle en JavaScript

La curryfication et l'application partielle sont des techniques de programmation fonctionnelle qui améliorent la modularité et la réutilisabilité de votre code JavaScript.

La curryfication et l'application partielle sont de puissantes techniques de programmation fonctionnelle qui peuvent améliorer considérablement la modularité et la réutilisabilité de votre code JavaScript. Toutes deux reposent sur les fermetures — la capacité d'une fonction interne à mémoriser les variables de la fonction externe qui l'a créée — ainsi une fonction retournée conserve les arguments que vous avez déjà fournis.

Cet article couvre ce qu'est la curryfication et pourquoi elle est importante, comment écrire un utilitaire curry réutilisable, en quoi l'application partielle diffère de la curryfication, des cas d'utilisation concrets, ainsi que les bonnes pratiques (et les pièges) à garder à l'esprit.

Comprendre la curryfication

La curryfication est une technique par laquelle une fonction est transformée en une séquence de fonctions, chacune prenant un seul argument. Elle vous permet de décomposer une fonction qui prend plusieurs arguments en une série de fonctions unaires (à un seul argument).

Exemple de curryfication

Considérons une fonction simple qui additionne trois nombres :

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

Nous pouvons transformer cette fonction en une version currifiée :

javascript— editable

Explication :

  • La fonction add prend trois arguments et retourne leur somme.
  • La fonction curryAdd est une version currifiée de add. Elle prend un argument a et retourne une autre fonction qui prend b. Cette deuxième fonction retourne encore une autre fonction qui prend c. La fonction la plus interne retourne la somme de a, b et c.

Avantages de la curryfication

  1. Réutilisabilité : Les fonctions currifiées vous permettent de créer de nouvelles fonctions en fixant certains arguments. Cela améliore la réutilisabilité en vous permettant de créer facilement des versions spécialisées d'une fonction sans dupliquer le code.
javascript— editable

Ici, curriedAdd est une version currifiée de la fonction add. Elle nous permet de créer des fonctions spécialisées comme add5 en fixant le premier argument (a) à 5. Cela favorise la réutilisation du code car nous pouvons créer plusieurs fonctions spécialisées sans répéter la logique d'addition.

  1. Composition de fonctions : La curryfication facilite la composition de fonctions. La composition de fonctions est le processus de combinaison de deux fonctions ou plus pour produire une nouvelle fonction.
javascript— editable

Dans cet exemple, nous composons les fonctions multiply et addOne grâce à la curryfication. La forme concise a => b => a * b s'appuie sur les fonctions fléchées, qui rendent les fonctions unaires imbriquées faciles à lire. En curryfiant ces fonctions, nous pouvons facilement créer une nouvelle fonction addOneThenMultiplyBy5, qui ajoute d'abord 1 à l'entrée (x) puis multiplie le résultat par 5. Cela illustre comment la curryfication facilite la composition de fonctions, simplifiant la création de nouvelles fonctions par combinaison de fonctions existantes.

Implémenter la curryfication en JavaScript

Nous pouvons créer une fonction utilitaire pour curryfier n'importe quelle fonction. Voici une implémentation d'une fonction de curryfication générique :

javascript— editable

Explication :

  1. Fonction de curryfication (curry) :

    • La fonction curry prend une autre fonction fn en entrée.
    • Elle retourne une nouvelle fonction appelée curried.
    • Cette fonction curried accepte un nombre quelconque d'arguments grâce à la syntaxe du paramètre rest (...args).
  2. Fonction currifiée (curried) :

    • À l'intérieur de curried, elle vérifie si le nombre d'arguments fournis (args.length) est supérieur ou égal au nombre d'arguments attendus par la fonction originale fn (fn.length).
    • Si suffisamment d'arguments sont fournis, elle appelle la fonction originale fn avec ces arguments via fn.apply(this, args).
    • Si le nombre d'arguments est insuffisant, elle retourne une nouvelle fonction qui accepte davantage d'arguments (nextArgs) grâce à l'opérateur de décomposition (...nextArgs).
    • Cette nouvelle fonction appelle récursivement curried avec les arguments combinés (args.concat(nextArgs)), garantissant que tous les arguments sont éventuellement collectés avant d'appeler la fonction originale fn.

    Remarque : fn.length ne comptabilise que les paramètres sans valeur par défaut et ignore les paramètres rest.

  3. Exemple d'utilisation :

    • Nous définissons une fonction multiply qui prend trois arguments et retourne leur produit.
    • Nous créons une version currifiée de la fonction multiply en la passant à la fonction curry, qui retourne une nouvelle fonction curriedMultiply.
    • Désormais, curriedMultiply peut être appelée avec un, deux ou trois arguments.
    • Chaque fois que nous appelons curriedMultiply avec un ou plusieurs arguments, elle retourne une nouvelle fonction jusqu'à ce que tous les arguments soient collectés, moment auquel elle retourne le résultat de la multiplication des arguments.

Explorer l'application partielle

L'application partielle est une technique par laquelle vous créez une nouvelle fonction en pré-remplissant certains arguments de la fonction originale. C'est particulièrement utile pour créer des fonctions spécialisées.

Exemple d'application partielle

Considérons la fonction suivante qui formate un message :

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

Nous pouvons créer une fonction partiellement appliquée :

javascript— editable

Explication :

  • La fonction formatMessage prend deux arguments, greeting et name, et retourne un message formaté.
  • La fonction partial prend une fonction fn et quelques arguments prédéfinis (...presetArgs). Elle retourne une nouvelle fonction qui prend les arguments restants (...laterArgs).
  • Lorsque la nouvelle fonction est appelée, elle combine presetArgs et laterArgs et appelle la fonction originale fn avec ces arguments.
  • En utilisant partial, nous créons greetHello, une fonction qui utilise toujours "Hello" comme salutation. Lorsqu'elle est appelée avec un nom, elle retourne le message complet.

Avantages de l'application partielle

  1. Simplification : Créer des fonctions plus simples à partir de fonctions plus complexes

    Supposons que nous ayons une fonction qui calcule le prix final d'un article après application d'une remise et d'une taxe.

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

Cette fonction nécessite trois arguments, ce qui la rend un peu fastidieuse à utiliser de manière répétée si les taux de remise et de taxe sont souvent identiques. Avec l'application partielle, nous pouvons simplifier cela.

javascript— editable

Dans l'exemple ci-dessus, applyDiscountAndTax est une fonction partiellement appliquée qui prédéfinit les valeurs de discount et tax. Cela facilite le calcul du prix final pour différents articles sans avoir à spécifier à chaque fois les taux de remise et de taxe.

  1. Réutilisabilité du code : Réutiliser la logique commune d'une fonction avec différents arguments prédéfinis

    Imaginons que nous ayons une fonction qui journalise des messages avec différents niveaux de sévérité.

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

Nous pouvons créer des fonctions réutilisables pour différents niveaux de journalisation grâce à l'application partielle.

javascript— editable

Ici, createLogger est une fonction partiellement appliquée qui fixe l'argument level. Les fonctions infoLogger et errorLogger peuvent désormais être utilisées pour journaliser des messages avec les niveaux prédéfinis, en réutilisant la logique commune de logMessage.

  1. Lisibilité améliorée : Rendre le code plus lisible en décomposant les fonctions complexes Considérons une fonction qui formate des dates dans différents styles.
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);
}

En utilisant l'application partielle, nous pouvons créer des fonctions plus lisibles pour différents formats de date.

javascript— editable

createDateFormatter applique partiellement l'argument format, produisant des fonctions spécifiques pour les formats de date US et EU. Cette décomposition rend le code plus lisible et plus facile à comprendre, car chaque fonction de formatage est dédiée à un format particulier.

Ces exemples illustrent comment l'application partielle en JavaScript peut simplifier les fonctions complexes, améliorer la réutilisabilité du code et en améliorer la lisibilité, rendant le code plus facile à gérer et à comprendre.

Curryfication vs. Application partielle

Ces deux techniques sont étroitement liées et souvent confondues, mais elles ne sont pas identiques :

  • La curryfication transforme une fonction de N arguments en N fonctions imbriquées prenant chacune exactement un argument. Une fonction entièrement currifiée est toujours appelée un argument à la fois : f(a)(b)(c).
  • L'application partielle fixe certains arguments d'une fonction et retourne une nouvelle fonction qui prend le reste en un seul appel : g = partial(f, a) puis g(b, c).

En résumé : la curryfication concerne la forme de la fonction (une chaîne d'appels unaires), tandis que l'application partielle concerne le pré-remplissage d'arguments. Notez que l'utilitaire générique curry présenté ci-dessus est plus flexible que la curryfication stricte — il accepte des arguments par groupes (curriedMultiply(2, 3)(4)), brouillant ainsi la frontière et supportant effectivement l'application partielle également.

javascript— editable

Bonnes pratiques pour utiliser la curryfication et l'application partielle

Garder les fonctions pures

  • Assurez-vous que les fonctions currifiées et partiellement appliquées restent pures, sans effets secondaires. Cela les rend plus faciles à raisonner et à tester.

Utiliser à bon escient

  • Utilisez la curryfication et l'application partielle lorsqu'elles s'adaptent naturellement au problème en question.
  • Évitez de surcharger votre code avec ces techniques, car elles peuvent le rendre plus difficile à comprendre si elles ne sont pas utilisées avec discernement.

Tirer parti de la composition de fonctions

  • Combinez des fonctions currifiées pour créer des fonctionnalités plus complexes. La curryfication fonctionne bien avec la composition de fonctions, menant à un code plus modulaire.

Documentation et nommage

  • Documentez correctement les fonctions currifiées et partiellement appliquées pour indiquer leur usage attendu.
  • Utilisez des noms clairs et descriptifs pour les fonctions afin de transmettre leur objectif.

Attention à ces pièges

  • fn.length n'est pas fiable pour la curryfication automatique. Un utilitaire générique curry qui repose sur fn.length se comportera mal avec des paramètres par défaut ou des paramètres rest, car ceux-ci ne sont pas comptabilisés. Si une fonction les utilise, passez l'arité attendue explicitement plutôt que de faire confiance à fn.length.
  • Une curryfication excessive nuit à la lisibilité. Une longue chaîne f(a)(b)(c)(d) est plus difficile à lire qu'un seul appel bien nommé. Recourez à la curryfication lorsqu'elle élimine véritablement la répétition.
  • Attention à this. Les fonctions fléchées n'ont pas leur propre this, donc une chaîne currifiée écrite avec des flèches ne peut pas être utilisée comme méthode reposant sur l'objet appelant. Si vous avez besoin du this dynamique, consultez la liaison de fonctions.
Info

Si vous utilisez fréquemment la curryfication et l'application partielle, envisagez d'utiliser la bibliothèque Lodash, qui fournit des fonctions utilitaires pratiques comme _.curry et _.partial.

Combiner avec les méthodes de tableau

La curryfication peut être efficacement combinée avec les méthodes de tableau comme map, filter et reduce pour un code concis et expressif.

javascript— editable

Explication :

  • La fonction curriedMultiply est utilisée pour créer multiplyByTwo, une fonction qui multiplie son argument par 2.
  • Le tableau numbers est transformé grâce à map, en appliquant multiplyByTwo à chaque élément, produisant un nouveau tableau de nombres doublés.

Conclusion

La curryfication et l'application partielle en JavaScript offrent de puissantes techniques pour simplifier la composition de fonctions, améliorer la réutilisabilité du code et en améliorer la lisibilité. La curryfication transforme les fonctions à arguments multiples en une série de fonctions unaires, permettant un code plus flexible et modulaire. L'application partielle permet de prédéfinir les arguments d'une fonction, facilitant la réutilisation du code et la simplification des fonctions complexes. En tirant parti de ces concepts de programmation fonctionnelle, les développeurs peuvent écrire du code JavaScript plus propre, plus concis et plus maintenable.

Pratique

Pratique
Qu'est-ce qui est exact concernant la curryfication en JavaScript ?
Qu'est-ce qui est exact concernant la curryfication en JavaScript ?
Was this page helpful?