Fermer

mars 9, 2022

Fonctions d'ordre supérieur en JavaScript : un guide pratique


L'une des caractéristiques de JavaScript qui le rend bien adapté à la programmation fonctionnelle est le fait qu'il peut accepter des fonctions d'ordre supérieur. Une fonction d'ordre supérieur est une fonction qui peut prendre une autre fonction comme argument ou qui renvoie une fonction comme résultat.

Fonctions de première classe : fonctions en tant qu'objets en JavaScript

Vous avez peut-être entendu dire que JavaScript traite les fonctions comme des citoyens de première classe. Cela signifie que les fonctions en JavaScript sont traitées comme des objets. Ils ont le genreObjetelles peuvent être affectées comme valeur d'une variable, et elles peuvent être transmises et renvoyées comme n'importe quelle autre variable de référence.

Cette capacité native confère à JavaScript des pouvoirs spéciaux en matière de programmation fonctionnelle. Parce que les fonctions sont des objets, le langage prend en charge une approche très naturelle de la programmation fonctionnelle. En fait, c'est tellement naturel que je parie que vous l'utilisez sans même y penser.

Comment les fonctions d'ordre supérieur prennent les fonctions comme arguments

Si vous avez fait beaucoup de programmation JavaScript basée sur le Web ou de développement frontal, vous avez probablement rencontré des fonctions qui utilisent un rappel. Un rappel est une fonction qui s'exécute à la fin d'une opération, une fois que toutes les autres opérations sont terminées. Habituellement, cette fonction de rappel est transmise en tant que dernier argument de la fonction. Souvent, il est défini inline comme une fonction anonyme.

Étant donné que JavaScript est monothread, ce qui signifie qu'une seule opération se produit à la fois, chaque opération qui va se produire est mise en file d'attente le long de ce thread unique. La stratégie consistant à transmettre une fonction à exécuter une fois le reste des opérations de la fonction parent terminée est l'une des caractéristiques de base des langages qui prennent en charge les fonctions d'ordre supérieur. Il permet un comportement asynchrone, de sorte qu'un script peut continuer à s'exécuter en attendant un résultat. La possibilité de transmettre une fonction de rappel est essentielle lorsqu'il s'agit de ressources susceptibles de renvoyer un résultat après une période de temps indéterminée.

Ceci est très utile dans un environnement de programmation Web, où un script peut envoyer une requête Ajax à un serveur, puis doit gérer la réponse chaque fois qu'elle arrive, sans connaître à l'avance la latence du réseau ou le temps de traitement sur le serveur. Node.js utilise fréquemment des rappels pour utiliser au mieux les ressources du serveur. Cette approche est également utile dans le cas d'une application qui attend l'entrée de l'utilisateur avant d'exécuter une fonction.

Par exemple, considérez cet extrait de JavaScript simple qui ajoute un écouteur d'événement à un bouton.

Alors Cliquable

document.getElementById("cliqueur").addEventListener("Cliquez sur", une fonction() {
alerte("tu as déclenché" + ce.identifiant);
});

Ce script utilise une fonction en ligne anonyme pour afficher une alerte. Mais il aurait tout aussi bien pu utiliser une fonction définie séparément et passer cette fonction nommée à laaddEventListenerméthode


 prouve le = une fonction() {
alerte("tu as déclenché" + ce.identifiant);
};

document.getElementById("cliqueur").addEventListener("Cliquez sur",prouve le);

Notez que nous sommes passésprouve leet pasprouve le()à notreaddEventListener une fonction. Lorsque vous transmettez une fonction par son nom sans parenthèses, vous transmettez l'objet fonction lui-même. Lorsque vous le transmettez entre parenthèses, vous transmettez le résultat de l'exécution de cette fonction.

Notre petitprouve le()est structurellement indépendante du code qui l'entoure, renvoyant toujours leidentifiant quel que soit l'élément déclenché. Ce bout de code peut exister dans n'importe quel contexte dans lequel vous souhaitez afficher une alerte avec leidentifiantd'un élément, et peut être appelée avec n'importe quel écouteur d'événement.

La possibilité de remplacer une fonction en ligne par une fonction définie et nommée séparément ouvre un monde de possibilités. Alors que nous essayons de développer des fonctions pures qui ne modifient pas les données externes et renvoient à chaque fois le même résultat pour la même entrée, nous disposons désormais de l'un des outils essentiels pour nous aider à développer une bibliothèque de petites fonctions ciblées pouvant être utilisées de manière générique dans n'importe quelle application.

Renvoyer des fonctions en tant que résultats avec des fonctions d'ordre supérieur

En plus de prendre des fonctions comme arguments, JavaScript permet aux fonctions de renvoyer d'autres fonctions en conséquence. Cela est parfaitement logique, puisque les fonctions sont simplement des objets, elles peuvent être renvoyées comme n'importe quelle autre valeur.

Mais que signifie renvoyer une fonction comme résultat ? Définir une fonction comme valeur de retour d'une autre fonction vous permet de créer des fonctions pouvant être utilisées comme modèles pour créer de nouvelles fonctions. Cela ouvre la porte à un autre monde de magie JavaScript fonctionnelle.

Par exemple, imaginez que vous en avez assez de lire tous ces articles sur la particularité deMillennialset vous décidez de remplacer le motMillennialsavec l'expressionGens de serpent chaque fois que cela se produit. Votre impulsion pourrait être simplement d'écrire une fonction qui a effectué ce remplacement de texte sur tout texte que vous lui avez passé :

 serpenter = une fonction(texte) {
retournertexte.remplacer(/la génération Y/ig, "Le peuple des serpents");
};
console.Journal(serpenter("Les Millenials préparent toujours quelque chose."));

Cela fonctionne, mais c'est assez spécifique à cette situation. Vous êtes également fatigué d'entendre parler de laBaby boomers . Vous aimeriez également créer une fonction personnalisée pour eux. Mais même avec une fonction aussi simple, vous ne voulez pas avoir à répéter le code que vous avez écrit :

 hippifier = une fonction(texte) {
retournertexte.remplacer(/Baby boomers/ig, "Les hippies vieillissants");
};
console.Journal(hippifier("Les baby-boomers regardent de l'autre côté."));

Mais que se passe-t-il si vous décidez de faire quelque chose de plus fantaisiste pour préserver la casse dans la chaîne d'origine ? Vous devrez modifier vos deux nouvelles fonctions pour ce faire. C'est un problème, et cela rend votre code plus fragile et plus difficile à lire.

Ce que vous voulez vraiment, c'est la flexibilité de pouvoir remplacer n'importe quel terme par n'importe quel autre terme dans une fonction de modèle et de définir ce comportement comme une fonction fondamentale à partir de laquelle vous pourriez générer toute une série de fonctions personnalisées.

Avec la possibilité de renvoyer des fonctions au lieu de valeurs, JavaScript offre des moyens de rendre ce scénario beaucoup plus pratique :

 attitude = une fonction(original,remplacement,la source) {
retourner une fonction(la source) {
retournerla source.remplacer(original,remplacement);
};
};

serpenter= attitude(/la génération Y/ig, "Le peuple des serpents");
hippifier= attitude(/Baby boomers/ig, "Les hippies vieillissants");

console.Journal(serpenter("Les Millenials préparent toujours quelque chose."));

console.Journal(hippifier("Les baby-boomers regardent de l'autre côté."));

Ce que nous avons fait, c'est isoler le code qui fait le travail réel dans un environnement polyvalent et extensibleattitudefonction qui encapsule tout le travail nécessaire pour modifier n'importe quelle chaîne d'entrée en utilisant une phrase originale et une phrase de remplacement avec une certaine attitude.

Définir une nouvelle fonction comme référence à laattitudefonction, pré-remplie avec les deux premiers arguments qu'elle prend, permet à la nouvelle fonction de prendre n'importe quel argument que vous lui passez et de l'utiliser comme texte source dans la fonction interne renvoyée par leattitudeune fonction.

Nous profitons ici du fait que les fonctions JavaScript ne se soucient pas de savoir si elles reçoivent le même nombre d'arguments qu'elles ont été définies à l'origine. Si un argument est manquant, la fonction traitera simplement les arguments manquants comme non définis.

D'autre part, cet argument supplémentaire peut être transmis ultérieurement lorsque la fonction appelée a été définie de la manière que nous venons de démontrer, en tant que référence à une fonction renvoyée par une autre fonction avec un argument (ou plus) non défini.

Revoyez cela plusieurs fois si vous en avez besoin, afin de bien comprendre ce qui se passe. Nous créons une fonction modèle qui renvoie une autre fonction. Ensuite, nous définissons cette fonction nouvellement renvoyée, moins un attribut, comme une implémentation personnalisée de la fonction de modèle. Toutes les fonctions créées de cette manière hériteront du même code de travail de la fonction modèle, mais peuvent être prédéfinies avec différents arguments par défaut.

Vous utilisez déjà des fonctions d'ordre supérieur

Les fonctions d'ordre supérieur sont si fondamentales pour le fonctionnement de JavaScript que vous les utilisez déjà. Chaque fois que vous passez une fonction anonyme ou un rappel, vous prenez en fait la valeur renvoyée par la fonction passée et vous l'utilisez comme argument pour une autre fonction (comme avecfonctions fléchées).

La capacité des fonctions à renvoyer d'autres fonctions étend la commodité de JavaScript, nous permettant de créer des fonctions nommées personnalisées pour effectuer des tâches spécialisées avec du code de modèle partagé. Chacune de ces petites fonctions peut hériter de toutes les améliorations apportées au code d'origine sur la route, ce qui nous aide à éviter la duplication de code et à garder notre source propre et lisible.

En prime, si vous vous assurez que vos fonctions sont pures afin qu'elles ne modifient pas les valeurs externes et qu'elles renvoient toujours la même valeur pour une entrée donnée, vous vous mettez en bonne position pour créer des suites de tests pour vérifier que votre code les modifications ne cassent rien sur lequel vous comptez lorsque vous mettez à jour les fonctions de votre modèle.

Commencez à réfléchir aux moyens de tirer parti de cette approche dans vos propres projets. L'un des avantages de JavaScript est que vous pouvez mélanger des techniques fonctionnelles directement avec le code que vous connaissez déjà. Essayez quelques expériences. Vous serez peut-être surpris de la facilité avec laquelle un peu de travail avec des fonctions d'ordre supérieur peut améliorer votre code.




Source link