Chapitre 14 – Fonctions avancées en JavaScript

Dans ce chapitre, nous allons explorer des concepts avancés autour des fonctions en JavaScript. Ces notions sont essentielles pour écrire un code plus expressif, modulaire et flexible. Elles vous permettront de maîtriser des techniques clés de la programmation fonctionnelle et de mieux comprendre certains comportements complexes du langage.

Zone de démonstration interactive

Les résultats apparaîtront ici...

1. Fonctions de rappel (callbacks)

Une fonction de rappel (ou callback) est une fonction que l'on passe en argument à une autre fonction, qui s'en servira pour continuer une opération ou déclencher une action spécifique une fois une tâche terminée.

function saluer(nom) {
  alert(`Bonjour, ${nom} !`);
}

function demanderNom(callback) {
  const nom = prompt("Quel est votre nom ?");
  callback(nom);
}

demanderNom(saluer);

Les callbacks sont souvent utilisés dans la gestion d'événements, les requêtes asynchrones ou les fonctions qui exécutent des traitements progressifs (comme Array.map(), forEach(), etc.).

let nombres = [1, 2, 3];
nombres.forEach(function(n) {
  console.log(n * 2);
});

2. Fonctions immédiatement invoquées (IIFE)

Les IIFE (Immediately Invoked Function Expressions) sont des fonctions qui s'exécutent automatiquement dès leur définition. Elles sont souvent utilisées pour créer une portée locale et protéger certaines variables de l'environnement global.

(function() {
  let secret = "Je suis privé";
  console.log("Fonction immédiatement invoquée");
})();

Cela permet notamment d'éviter les conflits de noms dans les scripts complexes ou combinés avec d'autres bibliothèques. C'était également très utilisé avant l'introduction des modules JavaScript ES6.

3. Fonctions retournant des fonctions

En JavaScript, une fonction peut retourner une autre fonction. Cela ouvre la porte à la création de fonctions dynamiques et de haut niveau, capables de générer du comportement personnalisé.

function multiplier(facteur) {
  return function(x) {
    return x * facteur;
  };
}

const doubler = multiplier(2);
const tripler = multiplier(3);

console.log(doubler(5)); // 10
console.log(tripler(5)); // 15

On utilise cela dans des librairies fonctionnelles ou pour créer des fonctions utilitaires réutilisables (ex : middleware, pipelines de traitement, etc.).

4. Portée et fermeture (closures)

Une fermeture (ou closure) est une fonction qui se souvient de l'environnement dans lequel elle a été créée. Elle garde l'accès aux variables de sa fonction parente, même après que cette dernière ait terminé son exécution.

function compteur() {
  let i = 0;
  return function() {
    i++;
    return i;
  };
}

const incrementer = compteur();
console.log(incrementer()); // 1
console.log(incrementer()); // 2
console.log(incrementer()); // 3

C'est un puissant outil pour créer des fonctions avec une mémoire interne, utile dans les cas où l'on souhaite encapsuler un état de manière contrôlée.

5. Fonctions fléchées et limitations

Les fonctions fléchées (=>) permettent une syntaxe concise. Cependant, elles n'ont pas leur propre this, ce qui peut être pratique ou problématique selon le contexte.

const personne = {
  nom: "Alice",
  saluer: function() {
    setTimeout(() => {
      console.log(`Bonjour, je suis ${this.nom}`);
    }, 1000);
  }
};

personne.saluer();

Ici, this.nom fonctionne parce que la fonction fléchée hérite du this du contexte parent. Si on avait utilisé function() classique, this aurait référé à undefined ou à window selon le mode strict.

Résumé du chapitre

  • Les callbacks permettent d'exécuter une fonction passée en paramètre, souvent après un traitement ou un événement.
  • Les IIFE créent des scopes locaux immédiatement exécutés, utiles pour isoler du code.
  • Les fonctions peuvent retourner d'autres fonctions, ce qui permet de construire du comportement dynamique.
  • Les closures permettent à une fonction d'accéder aux variables de sa portée d'origine même après la fin de cette portée.
  • Les fonctions fléchées ont une syntaxe courte et héritent du this de leur contexte, ce qui peut éviter certaines erreurs.

Ces concepts sont fondamentaux pour écrire un code JavaScript moderne, efficace et modulaire. Ils forment également la base de nombreux paradigmes avancés tels que la programmation fonctionnelle et les design patterns en JavaScript.