Maison  >  Article  >  interface Web  >  Explication détaillée de la combinaison de fonctions et du curry en JavaScript (avec exemples)

Explication détaillée de la combinaison de fonctions et du curry en JavaScript (avec exemples)

不言
不言avant
2018-10-13 14:42:471905parcourir

Cet article vous apporte une explication détaillée de la combinaison de fonctions JavaScript et du curry (avec des exemples). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Nous connaissons tous le principe de responsabilité unique, en fait, S (SRP, principe de responsabilité unique) dans SOLID orienté objet. En programmation fonctionnelle, chaque fonction est une unité et ne doit faire qu’une seule chose. Mais le monde réel est toujours complexe, et lorsqu’on mappe le monde réel à la programmation, une seule fonction n’a pas beaucoup de sens. À ce stade, la composition fonctionnelle et le curry sont nécessaires.

Appels chaînés

Si vous avez utilisé jQuery, vous savez tous ce que sont les appels chaînés. Par exemple, $('.post').eq(1).attr('data-test', 'test') Certaines des méthodes de chaîne et de tableau natives de JavaScript peuvent également écrire des appels chaînés. . Style :

'Hello, world!'.split('').reverse().join('') // "!dlrow ,olleH"

Tout d'abord, l'appel en chaîne est basé sur des objets Chacune des méthodes ci-dessus split, reverse, joinSi l'objet précédent détaché "Bonjour le monde ! " est Impossible de jouer.

En programmation fonctionnelle, les méthodes sont indépendantes des données. On peut écrire ce qui précède de manière fonctionnelle :

const split = (tag, xs) => xs.split(tag)
const reverse = xs => xs.reverse()
const join = (tag, xs) => xs.join(tag)

join('',reverse(split('','Hello, world!'))) // "!dlrow ,olleH"

Vous me direz certainement, vous plaisantez. En quoi est-ce mieux que les appels enchaînés ? Cela repose toujours sur les données. Sans transmettre « Bonjour tout le monde ! », votre série de combinaisons de fonctions ne fonctionnera pas. Le seul avantage est que les différentes méthodes peuvent être réutilisées. Pas de panique, il y aura tellement de contenu plus tard et je vais l'optimiser pour vous (bêtement). Avant de procéder à la transformation, nous introduisons d'abord deux concepts, l'application partielle et le curry.

Application partielle

L'application partielle est un processus qui traite les paramètres de la fonction. Elle reçoit certains paramètres puis renvoie une fonction qui reçoit moins de paramètres. Cela fait partie de l'application. Nous utilisons bind pour l'implémenter :

const addThreeArg = (x, y, z) => x + y + z;

const addTwoArg = addThreeNumber.bind(null, 1)
const addOneArg = addThreeNumber.bind(null, 1, 2)

addTwoArg(2, 3) // 6
addOneArg(7) // 10

Ce qui précède utilise bind pour générer deux autres fonctions, qui acceptent respectivement les paramètres restants. Cela fait partie de l'application. Bien sûr, vous pouvez le faire d'autres manières.

Problèmes avec certaines applications

Le principal problème avec certaines applications est que le type de fonction qu'elles renvoient ne peut pas être directement déduit. Comme mentionné précédemment, certaines applications renvoient une fonction qui accepte moins de paramètres sans spécifier le nombre de paramètres renvoyés. C'est quelque chose d'implicite, vous devez regarder le code. Ce n'est qu'alors que vous saurez combien de paramètres la fonction renvoyée reçoit.

Curried

Définition du Curried : Vous pouvez appeler une fonction sans lui passer tous les paramètres d'un coup. Cette fonction renverra une fonction pour recevoir les prochains paramètres et .

const add = x => y => x + y
const plusOne = add(1)
plusOne(10) // 11

Une fonction curry renvoie une fonction qui ne reçoit qu'un seul paramètre, et le type de fonction renvoyé est prévisible.

Bien sûr, dans le développement actuel, il existe de nombreuses fonctions qui ne sont pas curryées. Nous pouvons utiliser certaines fonctions de l'outil pour les convertir :

const curry = (fn) => { // fn可以是任何参数的函数
  const arity = fn.length;

  return function $curry(...args) {
    if (args.length <p>Vous pouvez également utiliser la bibliothèque open source Ramda. méthode du curry. </p><h3>Oh, le curry. A quoi ça sert ? </h3><p>Par exemple</p><pre class="brush:php;toolbar:false">const currySplit = curry((tag, xs) => xs.split(tag))
const split = (tag, xs) => xs.split(tag)

// 我现在需要一个函数去split ","

const splitComma = currySplit(',') //by curry

const splitComma = string => split(',', string)

Vous pouvez voir que lorsqu'une fonction curry génère une nouvelle fonction, cela n'a rien à voir avec les données. En comparant les deux processus de génération de nouvelles fonctions, celui sans curry est relativement verbeux.

Composition de la fonction

Donnez d'abord le code :

const compose = (...fns) => (...args) => fns.reduceRight((res, fn) => [fn.call(null, ...res)], args)[0];

En fait, compose fait un total de deux choses :

  1. Recevoir une fonction Groupe, renvoie une fonction, n'exécute pas la fonction immédiatement

  2. Fonction combinaison, combine les fonctions qui lui sont transmises de gauche à droite.

Certains étudiants ne connaissent peut-être pas très bien le réduireRight ci-dessus, je vais vous donner un exemple de 2 yuans et 3 yuans :

const compose = (f, g) => (...args) => f(g(...args))
const compose3 = (f, g, z) => (...args) => f(g(z(...args)))

Les appels de fonction proviennent de. de gauche à droite, le flux de données est également le même de gauche à droite. Bien sûr, vous pouvez définir de droite à gauche, mais cela n'a pas de sens sémantique.

Bien, optimisons maintenant l'exemple initial :

const split = curry((tag, xs) => xs.split(tag))
const reverse = xs => xs.reverse()
const join = curry((tag, xs) => xs.join(tag))

const reverseWords = compose(join(''), reverse, split(''))

reverseWords('Hello,world!');

Est-ce beaucoup plus simple et plus facile à comprendre ? Le reverseWords ici est aussi le style de code Pointfree dont nous avons parlé précédemment. Elle ne repose pas sur des données ou un état externe, c'est une fonction combinée.

Pointfree J'ai présenté la programmation fonctionnelle JS - le concept dans l'article précédent, et j'ai également expliqué ses avantages et ses inconvénients. Les amis intéressés peuvent y jeter un œil.

Loi associative de combinaison de fonctions

Révisez d'abord les connaissances de l'école primaire sur la loi associative d'addition : a+(b+c)=(a+b)+c. Je ne vais pas l'expliquer, vous devriez pouvoir comprendre.

Avec le recul, les combinaisons de fonctions ont en fait des lois associatives :

compose(f, compose(g, h)) === compose(compose(f, g), h);

C'est un avantage pour notre programmation. Nos combinaisons de fonctions peuvent être combinées et mises en cache à volonté :

const split = curry((tag, xs) => xs.split(tag))
const reverse = xs => xs.reverse()
const join = curry((tag, xs) => xs.join(tag))

const getReverseArray = compose(reverse, split(''))

const reverseWords = compose(join(''), getReverseArray)

reverseWords('Hello,world!');
.

Supplément de carte cérébrale :

Explication détaillée de la combinaison de fonctions et du curry en JavaScript (avec exemples)


Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer