Cette fonctionnalité du langage JavaScript peut vous aider à ranger votre code et vous donnera une nouvelle appréciation du fonctionnement des fonctions.
Les fonctions Curried peuvent aider à rendre votre code JavaScript plus lisible et expressif. La technique de currying est idéale lorsque vous souhaitez décomposer une logique complexe en morceaux de code plus petits, autonomes et plus gérables.
Apprenez tout sur les fonctions curry en JavaScript, comment utiliser la technique de curry de fonctions pour créer fonctions partiellement appliquées, ainsi que des cas d'utilisation réels pour les fonctions curry et partiellement appliquées les fonctions.
Qu’est-ce que le curry?
Le curry doit son nom au mathématicien Haskell B. Curry, et le concept dérive du calcul Lambda. Le currying prend une fonction qui reçoit plus d'un paramètre et la divise en une série de fonctions unaires (à un paramètre). En d’autres termes, une fonction curry ne prend qu’un seul paramètre à la fois.
Un exemple de base de curry
Vous trouverez ci-dessous un exemple de fonction curry :
functionbuildSandwich(ingredient1) {
return(ingredient2) => {
return(ingredient3) => {
return`${ingredient1},${ingredient2},${ingredient3}`
}
}
}
Le construireSandwich() la fonction renvoie une autre fonction - une fonction anonyme qui reçoit le ingrédient2 argument. Ensuite, cette fonction anonyme renvoie une autre fonction anonyme qui reçoit ingrédient3. Enfin, cette dernière fonction renvoie le modèle littéral, une façon de formatage des chaînes en JavaScript.
Ce que vous avez créé est une fonction imbriquée où chaque fonction appelle celle en dessous jusqu'à la fin. Maintenant, quand tu appelles construireSandwich() et transmettez-lui un seul paramètre, il renverra la partie de la fonction dont vous n'avez pas encore fourni les arguments :
console.log(buildSandwich("Bacon"))
Vous pouvez voir dans le résultat que buildSandwich renvoie une fonction :
Pour terminer l'appel de fonction, vous devez fournir les trois arguments :
buildSandwich("Bacon")("Lettuce")("Tomato")
Ce code transmet « Bacon » à la première fonction, « Laitue » à la seconde et « Tomate » à la dernière fonction. En d'autres termes, le construireSandwich() La fonction est en réalité divisée en trois fonctions, chaque fonction ne recevant qu'un seul paramètre.
Bien qu'il soit parfaitement valable de curry en utilisant les fonctions traditionnelles, toute l'imbrication peut devenir assez moche à mesure que l'on s'enfonce. Pour contourner ce problème, vous pouvez utiliser les fonctions fléchées et profiter de leur syntaxe plus claire :
const buildMeal = ingred1 =>ingred2 =>ingred3 =>
`${ingred1}, ${ingred2}. ${ingred3}`;
Cette version refactorisée est plus concise, un avantage de l'utilisation fonctions fléchées vs fonctions régulières. Vous pouvez appeler la fonction de la même manière que la précédente :
buildMeal("Bacon")("Lettuce")("Tomato")
Fonctions de curry partiellement appliquées
Les fonctions partiellement appliquées sont une utilisation courante du curry. Cette technique consiste à fournir uniquement les arguments nécessaires à la fois (plutôt que de fournir tous les arguments). Chaque fois que vous invoquez une fonction en passant tous les paramètres requis, vous dites que vous avez « appliqué » cette fonction.
Regardons un exemple :
const multiply = (x, y) => x * y;
Vous trouverez ci-dessous la version au curry de multiplier :
const curriedMultiply = x =>y => x * y;
Le curriedMultiply() la fonction reçoit le X argument pour la première fonction et oui pour la deuxième fonction, il multiplie ensuite les deux valeurs.
Pour créer la première fonction partiellement appliquée, appelez curriedMultiple() avec le premier paramètre et assignez la fonction renvoyée à une variable :
const timesTen = curriedMultiply(10)
À ce stade, le code a « partiellement appliqué » le curriedMultiply() fonction. Alors quand tu veux appeler foisDix(), il vous suffit de lui transmettre un numéro et le nombre sera automatiquement multiplié par 10 (qui est stocké dans la fonction appliquée) :
console.log(timesTen(8)) // 80
Cela vous permet de vous appuyer sur une seule fonction complexe en créant plusieurs fonctions personnalisées à partir de celle-ci, chacune avec sa propre fonctionnalité verrouillée.
Jetez un œil à un exemple plus proche d’un cas d’utilisation réel de développement Web. Ci-dessous vous avez un updateElemText() fonction qui prend le nom d'un élément identifiant lors du premier appel, le contenu lors du deuxième appel, puis met à jour l'élément en fonction du identifiant et le contenu que vous lui avez fourni :
const updateElemText = id = content
=> document.querySelector(`#${id}`).textContent = content// Lock the element's id into the function:
const updateHeaderText = updateElemText('header')
// Update the header text
updateHeaderText("Hello World!")
Composition fonctionnelle avec fonctions au curry
Une autre utilisation courante du curry est la composition fonctionnelle. Cela vous permet d'appeler de petites fonctions, dans un ordre spécifique, et de les combiner en une seule fonction plus complexe.
Par exemple, dans un hypothétique site de commerce électronique, voici trois fonctions que vous souhaiterez peut-être exécuter les unes après les autres (dans un ordre précis) :
const addCustomer = fn =>(...args) => {
console.log("Saving customer info")
return fn(...args)
}const processOrder = fn =>(...args) => {
console.log(`processing order #${args[0]}`)
return fn(...args);
}
let completeOrder = (...args) => {
console.log(`Order #${[...args].toString()} completed.`);
}
Notez que ce code utilise le laisser mot-clé pour définir le Complétez la commande() fonction. Cela vous permet de réaffecter une valeur à la variable et fait partie de comment fonctionne la portée en JavaScript.
Ensuite, vous devez appeler les fonctions dans l'ordre inverse (de l'intérieur vers l'extérieur) car vous souhaitez d'abord ajouter les clients :
completeOrder = (processOrder(completeOrder));
completeOrder = (addCustomer(completeOrder));
completeOrder("1000")
Cela vous donnera le résultat suivant :
Si vous deviez écrire les fonctions ci-dessus de la manière habituelle, le code ressemblerait à ceci :
functionaddCustomer(...args) {
returnfunctionprocessOrder(...args) {
returnfunctioncompleteOrder(...args) {
// end
}
}
}
Quand tu appelles le addClient() fonction et transmettez les arguments, vous commencez de l'intérieur et progressez vers le haut de la fonction.
Convertir une fonction normale en fonction curry avec une fonction curry
Si vous envisagez d'utiliser beaucoup les fonctions de curry, vous pouvez rationaliser le processus avec une fonction d'assistance.
Cette fonction convertira n'importe quelle fonction normale en fonction au curry. Il utilise la récursion pour gérer n'importe quel nombre d'arguments.
const curry = (fn) => {
return curried = (...args) => {
if (fn.length !== args.length) {
return curried.bind(null, ...args)
}
return fn(...args);
}
}
Cette fonction acceptera toute fonction écrite standard qui reçoit plus d'un paramètre, renvoyant une version curry de cette fonction. Pour le voir en action, utilisez cet exemple de fonction qui prend trois paramètres et les additionne :
const total = (x, y, z) => x + y + z
Pour convertir cette fonction, appelez le curry() fonction et réussite total comme argument :
const curriedTotal = curry(total)
Maintenant, pour appeler la fonction, il vous suffit de passer tous les arguments :
console.log(curriedTotal(10)(20)(30)) // 60
En savoir plus sur les fonctions en JavaScript
Les fonctions de JavaScript sont extrêmement flexibles et les fonctions de curry ne représentent qu'une petite partie de cela. Il existe de nombreux autres types de fonctions telles que les fonctions fléchées, les fonctions constructeur et les fonctions anonymes. Se familiariser avec ces fonctions et leurs composants est essentiel pour maîtriser JavaScript.