Fonction pure en JavaScript : mêmes entrées, mêmes sorties, aucun effet

Une fonction pure renvoie toujours le même résultat pour les mêmes arguments et ne modifie rien à l'extérieur. Deux conditions, beaucoup de bénéfices.
3 min de lecture
Believemy logo

Certaines fonctions se comportent comme une formule de tableur : donnez-leur les mêmes entrées, elles rendent toujours la même sortie, et rien d'autre ne bouge dans le programme.

Ces fonctions sont dites pures. Elles se testent sans préparation, se relisent sans contexte, et se déplacent d'un fichier à l'autre sans surprise.


Définition

Une fonction pure respecte deux conditions simultanément. Elle renvoie toujours le même résultat pour les mêmes arguments, et elle ne produit aucun Effet de bord, c'est-à-dire aucune modification en dehors d'elle-même.

JAVASCRIPT
function totalTTC(prixHT, taux) {
  return prixHT * (1 + taux);
}

console.log(totalTTC(100, 0.2)); // 120
console.log(totalTTC(100, 0.2)); // 120, toujours

let remise = 0.1;
function totalImpur(prixHT) {
  return prixHT * (1 - remise); // dépend d'une variable extérieure
}

console.log(totalImpur(100)); // 90
remise = 0.5;
console.log(totalImpur(100)); // 50, même appel, autre résultat

La seconde fonction n'est pas fausse, elle est simplement imprévisible en isolation : son résultat dépend d'une valeur qui n'apparaît nulle part dans son appel.


Le deuxième piège : modifier ses arguments

Une fonction peut renvoyer la bonne valeur et rester impure, parce qu'elle a modifié au passage ce qu'on lui a confié.

JAVASCRIPT
function ajouterImpur(liste, article) {
  liste.push(article); // modifie l'argument reçu
  return liste;
}

function ajouterPur(liste, article) {
  return [...liste, article];
}

const panier = ["clavier"];
ajouterPur(panier, "souris");
console.log(panier.length); // 1, l'original est intact

ajouterImpur(panier, "souris");
console.log(panier.length); // 2

La version pure produit une nouvelle liste avec le Spread (...). C'est le principe de l'Immuabilité, appliqué à l'échelle d'une fonction.


Les impuretés qui se cachent

  • Math.random() et Date.now() : deux appels identiques, deux résultats. Passez la valeur en argument.
  • La lecture d'une variable extérieure : le résultat dépend d'un état invisible depuis l'appel.
  • La modification d'un objet reçu : l'appelant se retrouve avec une donnée qu'il n'a pas changée.
  • L'écriture d'un journal ou d'un stockage : même sans changer le résultat, c'est un effet.
Bon à savoir

Une fonction pure est mémoïsable par construction : puisque le résultat ne dépend que des arguments, le cache ne peut pas se tromper. Voir Mémoïsation.


Questions fréquentes

Question

Tout un programme peut-il être pur ?

Non, et ce n'est pas le but. Un programme qui n'écrit rien, n'affiche rien et n'appelle aucun service ne sert à rien. L'objectif est de rassembler les effets à la lisière du code et de garder pur tout ce qui calcule, ce qui représente souvent la majeure partie d'une application.


Question

Une fonction pure peut-elle appeler une autre fonction ?

Oui, à condition que celle-ci soit pure elle aussi. La pureté se propage : une fonction qui n'appelle que des fonctions pures et ne touche à rien d'extérieur reste pure. Un seul appel impur dans la chaîne suffit en revanche à contaminer l'ensemble.


Question

Quel bénéfice concret pour les tests ?

Un test de fonction pure tient en une ligne : on appelle avec des valeurs, on compare le retour. Aucune base à préparer, aucun service à simuler, aucun nettoyage après coup. C'est la raison pour laquelle un Test unitaire sur du code impur est presque toujours plus long à écrire qu'à faire passer.

Termes connexes

Découvrez notre glossaire JavaScript

Tous les mots de JavaScript expliqués simplement : mots-clés, objets natifs, méthodes, erreurs et concepts. Définitions claires et exemples qui tournent, pour apprendre et pour se dépanner.

Partager cet article

Tu veux nous aider ? Fais un lien vers cet article sur tes réseaux ou encore mieux : sur ton site, dans un article ou dans ta newsletter.