Les fonctions pures sont des fonctions qui ne produisent pas d’effets secondaires et qui, lorsqu’elles sont appelées avec les mêmes paramètres d’entrée, renvoient toujours le même résultat.
Vous pouvez utiliser des fonctions pures pour vous assurer que votre code est propre, maintenable et testable. Ces fonctions sont idéales pour ces tâches car elles sont prévisibles et ne modifient pas les états externes.
Elles sont également plus faciles à déboguer, ce qui les rend utiles dans le développement de systèmes logiciels complexes. Vous découvrirez ici les fonctions pures en JavaScript, leurs caractéristiques et leurs avantages.
Caractéristiques d’une fonction pure
Pour qu’une fonction soit « pure », elle doit satisfaire à quelques exigences.
Valeur de retour constante
Une fonction pure doit toujours renvoyer la même valeur pour une même entrée, quel que soit le nombre de fois où elle est appelée.
Prenons l’exemple de la fonction ci-dessous :
function multiply(a, b) {
return a * b;
}
La fonction multiplier dans l’exemple ci-dessus renvoie toujours le produit de ses deux arguments. Pour un même ensemble d’arguments, sa valeur de retour est constante.
Si vous appelez cette fonction plusieurs fois avec les mêmes arguments, vous obtiendrez toujours la même valeur. Par exemple :
multiply(2, 3); // returns 6
multiply(2, 3); // returns 6
multiply(2, 3); // returns 6
On peut aussi considérer l’exemple ci-dessous :
function multiplyRandomNumber(num) {
return num * Math.floor(Math.random() * 10);
}
multiplyRandomNumber(5); // Unpredictable results
multiplyRandomNumber(5); // Unpredictable results
multiplyRandomNumber(5); // Unpredictable results
Le multiplierNombreRandom ci-dessus renverra des résultats différents à chaque fois que vous l’appellerez, ce qui la rend impure. Les résultats de cette fonction étant imprévisibles, il est difficile de tester les composants qui s’appuient sur elle.
Pas d’effets secondaires
Une fonction pure ne doit pas produire d’effets secondaires. Un effet de bord se réfère à toute modification de l’état ou du comportement en dehors de la portée de la fonction, telle que la modification des variables globales, la sortie de la console, les requêtes réseau ou la manipulation du DOM.
Lorsqu’une fonction pure a un effet secondaire, elle n’est plus pure car elle affecte un état externe et viole le principe d’absence d’effets secondaires observables. Par conséquent, les fonctions pures évitent les effets secondaires afin de garantir qu’elles ne modifient pas l’état du programme.
Prenons l’exemple suivant :
let count = 0;
function increment() {
count++;
console.log(count);
}
increment(); // Logs 1
increment(); // Logs 2
increment(); // Logs 3
Le l’incrément dans cet exemple a pour effet secondaire de modifier la fonction compte en dehors de son champ d’application. Il affiche également un journal dans la console.
Cette fonction n’est pas pure parce qu’elle a un effet secondaire, ce qui peut rendre plus difficile la prédiction de sa sortie et le test en isolation. Pour la rendre pure, vous pouvez la modifier pour qu’elle prenne en compte l’effet secondaire compte comme argument et renvoie la valeur incrémentée sans modifier l’état externe.
Comme ça :
function increment(count) {
return count + 1;
}
increment(1); // returns 2
increment(1); // returns 2
increment(1); // returns 2
La version du incrémentale dans l’exemple ci-dessus n’a pas d’effets de bord car elle ne modifie aucune variable externe et n’enregistre aucune valeur. En outre, quel que soit le nombre de fois où vous l’appelez, elle renvoie la même valeur pour la même entrée. Il s’agit donc d’une fonction pure.
Autres caractéristiques
En plus d’avoir une valeur de retour constante et de ne pas produire d’effets secondaires, vous devez respecter les règles suivantes lorsque vous créez une fonction JavaScript que vous souhaitez pure :
- Votre fonction ne doit modifier aucun de ses arguments. Au lieu de cela, si une opération nécessite une mutation, faites une copie de l’argument et mutez la copie.
- Votre fonction doit toujours avoir une valeur de retour. Si votre fonction n’a pas de valeur de retour ou d’effets secondaires, elle ne peut rien faire !
- Votre fonction ne doit pas dépendre d’un état externe.
Avantages des fonctions pures
Les fonctions pures présentent certains avantages par rapport aux fonctions impures, dont les suivants.
Testabilité
Les fonctions pures sont faciles à tester car leur comportement d’entrée/sortie est bien défini. De plus, les fonctions pures ne dépendent pas d’un état externe ou d’effets secondaires. Par conséquent, vous pouvez les tester de manière isolée sans vous soucier des dépendances ou des interactions avec d’autres parties du programme.
En revanche, tester des fonctions impures qui dépendent d’un état externe ou produisent des effets secondaires peut s’avérer plus difficile, car leur comportement peut dépendre de l’état du programme ou d’autres facteurs externes. Il est donc plus difficile de créer des cas de test complets et de s’assurer que la fonction se comporte correctement dans tous les scénarios.
Mémoïsation
Comme les fonctions pures produisent toujours la même sortie pour la même entrée et ne produisent pas d’effets secondaires, vous pouvez facilement les mémoriser.
En vous appuyant sur ces propriétés et en utilisant la mémorisation, vous pouvez mettre en cache le résultat d’un appel à une fonction pure pour une entrée spécifique. Votre fonction peut alors renvoyer le résultat mis en cache la prochaine fois qu’elle est appelée avec la même entrée.
La mémorisation des fonctions pures peut améliorer les performances d’un programme, en particulier pour les calculs coûteux qui traitent de manière répétée la même entrée, sans se soucier de l’interférence avec l’état du programme.
En revanche, les fonctions impures peuvent produire des résultats différents pour la même entrée, en fonction de l’état du programme ou de facteurs externes. Cela les rend difficiles à mémoriser car le résultat mis en cache peut ne plus être valide si les dépendances de la fonction ou l’état externe changent entre les appels.
Concurrence
Étant donné que les fonctions pures ne modifient aucun état externe et ne produisent aucun effet secondaire, elles sont sûres pour les threads. Vous pouvez les exécuter simultanément sans vous soucier des conditions de course ou des problèmes de synchronisation.
En revanche, les fonctions impures peuvent être difficiles à exécuter simultanément, car elles peuvent interférer les unes avec les autres ou produire un comportement inattendu lorsqu’elles sont exécutées en parallèle. Par exemple, si deux threads accèdent à la même variable globale et la modifient, ils peuvent écraser les modifications de l’autre ou produire des résultats incohérents.
Fonctions pures et fonctions impures
Vous pouvez écrire des programmes en utilisant une combinaison de fonctions pures et impures, car chaque type a son utilité.
Les fonctions pures sont faciles à optimiser, à tester et à paralléliser, ce qui les rend adaptées à des cas d’utilisation tels que la programmation fonctionnelle, la mise en cache, les tests, la programmation parallèle et les tâches de traitement des données.
Cependant, les fonctions impures posent des problèmes de test et de concurrence, mais sont utiles lorsqu’on travaille avec des structures de données mutables ou qu’on interagit avec des systèmes et des ressources externes.