Fermer

mai 7, 2022

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


Les fonctions qui prennent une autre fonction comme argument ou qui définissent une fonction comme valeur de retour sont appelées fonctions d’ordre supérieur.

JavaScript peut accepter des fonctions d’ordre supérieur. Cette capacité à gérer des fonctions d’ordre supérieur, entre autres caractéristiques, fait de JavaScript l’un des langages de programmation bien adaptés pour programmation fonctionnelle.

JavaScript traite les fonctions comme des citoyens de première classe

Vous avez peut-être entendu dire que les fonctions JavaScript sont des citoyens de première classe. Cela signifie que les fonctions en JavaScript sont des objets.

Ils ont le genre Objectelles 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.

Les fonctions de première classe confèrent à JavaScript des pouvoirs spéciaux et nous permettent de bénéficier de fonctions d’ordre supérieur.

Parce que les fonctions sont des objets, JavaScript est l’un des langages de programmation populaires qui prend en charge une approche naturelle de la programmation fonctionnelle.

En fait, les fonctions de première classe sont tellement natives de l’approche de JavaScript que je parie que vous les avez utilisées sans même y penser.

Les fonctions d’ordre supérieur peuvent prendre une fonction comme argument

Si vous avez fait beaucoup de développement Web JavaScript, vous avez probablement rencontré des fonctions qui utilisent un rappel.

Une fonction de 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, nous passons cette fonction comme argument en dernier, après les autres paramètres. Il est souvent défini en ligne comme une fonction anonyme. Les fonctions de rappel reposent sur la capacité de JavaScript à gérer des fonctions d’ordre supérieur.

JavaScript est un langage monothread. Cela signifie qu’une seule opération peut être exécutée à la fois.

Pour éviter que les opérations ne se bloquent entre elles ou que le thread principal du système ne se bloque (ce qui entraînerait un blocage), le moteur s’assure que toutes les opérations s’exécutent dans l’ordre. Ils sont mis en file d’attente le long de ce thread unique jusqu’à ce qu’il soit sûr qu’une autre transaction de code se produise.

La possibilité de transmettre une fonction en tant qu’argument et de l’exécuter une fois les autres opérations de la fonction parent terminées est essentielle pour qu’un langage prenne en charge les fonctions d’ordre supérieur.

Les fonctions de rappel en JavaScript permettent un comportement asynchrone, de sorte qu’un script peut continuer à exécuter d’autres fonctions ou opérations 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.

Ce modèle de fonction d’ordre supérieur est très utile dans un développement Web. Un script peut envoyer une requête à un serveur, puis avoir besoin de gérer la réponse chaque fois qu’elle arrive, sans nécessiter aucune connaissance de la latence du réseau ou du temps de traitement du serveur.

Node.js utilise fréquemment des fonctions de rappel pour utiliser efficacement les ressources du serveur. Cette approche asynchrone est également utile dans le cas d’une application qui attend l’entrée de l’utilisateur avant d’exécuter une fonction.

Exemple : transmission d’une fonction d’alerte à un écouteur d’événement d’élément

Considérez cet extrait de JavaScript simple qui ajoute un écouteur d’événement à un bouton.

So Clickable

document.getElementById("clicker").addEventListener("click", function() {
alert("you triggered " + this.id);
});

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 à la addEventListener méthode:

var proveIt = function() {
alert("you triggered " + this.id);
};

document.getElementById("clicker").addEventListener("click", proveIt);

Nous n’avons pas seulement démontré des fonctions d’ordre supérieur en faisant cela. Nous avons rendu notre code plus lisible et résilient, et avons séparé les fonctionnalités pour différentes tâches (écouter les clics ou alerter l’utilisateur).

Comment les fonctions d’ordre supérieur prennent en charge la réutilisation du code

Notre petit proveIt() est structurellement indépendante du code qui l’entoure, renvoyant toujours le id quel que soit l’élément déclenché. Cette approche de la conception de fonctions est au cœur de la programmation fonctionnelle.

Ce bout de code peut exister dans n’importe quel contexte où vous affichez une alerte avec le id d’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.

En programmation fonctionnelle, 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 avons maintenant l’un des outils essentiels pour nous aider à développer une bibliothèque de petites fonctions d’ordre supérieur ciblées que vous pouvez utiliser de manière générique dans n’importe quelle application.

Remarque : Passer des fonctions par rapport à passer l’objet de fonction

Notez que nous sommes passés proveIt et pas proveIt() à notre addEventListener 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.

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 a du sens puisque les fonctions sont simplement des objets. Les objets (y compris les fonctions) peuvent être définis comme la valeur renvoyée par une fonction, tout comme les chaînes, les tableaux ou d’autres valeurs.

Mais que signifie renvoyer une fonction comme résultat ?

Les fonctions sont un moyen puissant de décomposer les problèmes et de créer des morceaux de code réutilisables. Lorsque nous définissons une fonction comme la valeur de retour d’une fonction d’ordre supérieur, elle peut servir de modèle pour de nouvelles fonctions !

Cela ouvre la porte à un autre monde de magie JavaScript fonctionnelle.

Supposons que vous ayez lu un trop grand nombre d’articles sur Millennials et s’ennuyer. Vous décidez de remplacer le mot Millennials avec l’expression Gens 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é :

var snakify = function(text) {
return text.replace(/millenials/ig, "Snake People");
};
console.log(snakify("The Millenials are always up to something."));

Cela fonctionne, mais c’est assez spécifique à cette situation. Peut-être que votre patience a aussi dépassé les articles sur le Baby 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 lorsque vous pouvez commencer avec une fonction d’ordre supérieur à la place.

var hippify = function(text) {
return text.replace(/baby boomers/ig, "Aging Hippies");
};
console.log(hippify("The Baby Boomers just look the other way."));

Mais que se passerait-il si vous décidiez de faire quelque chose de plus fantaisiste pour préserver le boîtier 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. Dans des situations comme celle-ci, nous pouvons utiliser une fonction d’ordre supérieur comme solution.

Création d’un modèle de fonction d’ordre supérieur

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 pouvez créer de nouvelles fonctions personnalisées.

Avec la possibilité d’assigner des fonctions comme valeurs de retour, JavaScript offre des moyens de rendre ce scénario beaucoup plus pratique :

var attitude = function(original, replacement, source) {
return function(source) {
return source.replace(original, replacement);
};
};

var snakify = attitude(/millenials/ig, "Snake People");
var hippify = attitude(/baby boomers/ig, "Aging Hippies");

console.log(snakify("The Millenials are always up to something."));

console.log(hippify("The Baby Boomers just look the other way."));

Ce que nous avons fait, c’est isoler le code qui fait le travail réel dans un environnement polyvalent et extensible attitude une fonction. Il encapsule tout le travail nécessaire pour modifier toute chaîne d’entrée en utilisant la phrase d’origine comme valeur initiale et génère une phrase de remplacement avec une certaine attitude.

Que gagne-t-on à définir cette nouvelle fonction comme une référence à la attitude fonction d’ordre supérieur, pré-remplie avec les deux premiers arguments qu’elle prend ? Cela permet à la nouvelle fonction de prendre le texte que vous lui transmettez et d’utiliser cet argument dans la fonction de retour que nous avons définie comme attitude sortie de la fonction.

Les fonctions JavaScript ne se soucient pas du nombre d’arguments que vous leur transmettez.

Si le deuxième argument est manquant, il le traitera comme indéfini. Et il en sera de même si nous choisissons de ne pas fournir de troisième argument, ni aucun nombre d’arguments supplémentaires.

De plus, vous pouvez transmettre cet argument supplémentaire ultérieurement. Vous pouvez le faire lorsque vous avez défini la fonction d’ordre supérieur que vous souhaitez appeler, comme nous venons de le démontrer.

Définissez-le simplement comme une référence à une fonction renvoyée par une fonction d’ordre supérieur avec un ou plusieurs arguments non définis.

Revoyez cela plusieurs fois si vous en avez besoin, afin de bien comprendre ce qui se passe.

Nous créons un modèle de fonction d’ordre supérieur 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 que vous créez de cette manière hériteront du code de travail de la fonction d’ordre supérieur. Cependant, vous pouvez les prédéfinir 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 de 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 avec fonctions fléchées).

Les développeurs se familiarisent avec les fonctions d’ordre supérieur au début du processus d’apprentissage de JavaScript. C’est tellement inhérent à la conception de JavaScript que le besoin d’apprendre le concept des fonctions fléchées ou des rappels peut ne survenir que plus tard.

La possibilité d’assigner des fonctions qui renvoient d’autres fonctions étend la commodité de JavaScript. Les fonctions d’ordre supérieur nous permettent de créer des fonctions nommées personnalisées pour effectuer des tâches spécialisées avec du code de modèle partagé à partir d’une fonction de premier ordre.

Chacune de ces fonctions peut hériter des améliorations apportées ultérieurement à la fonction d’ordre supérieur. Cela nous aide à éviter la duplication de code et à garder notre code source propre et lisible.

Si vous vous assurez que vos fonctions sont pures (elles ne modifient pas les valeurs externes et renvoient toujours la même valeur pour une entrée donnée), vous pouvez créer des tests pour vérifier que vos modifications de code ne cassent rien lorsque vous mettez à jour vos fonctions de premier ordre. .

Conclusion

Maintenant que vous savez comment fonctionne une fonction d’ordre supérieur, vous pouvez commencer à réfléchir à la manière dont vous pouvez tirer parti du concept 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. Même si vous commencez par utiliser une fonction d’ordre supérieur pour le plaisir, vous vous familiariserez assez vite avec la flexibilité supplémentaire qu’elle offre.

Un peu de travail avec des fonctions d’ordre supérieur peut maintenant améliorer votre code pour les années à venir.




Source link