Initialisation des systèmes...

Baptiste.Dev
Retour aux notes
LangagesIntermédiaireSérie : JavaScript

JavaScript : Portée & closures

Où vivent les variables (portée globale, de fonction, de bloc), le hoisting, et les closures : le mécanisme qui fait tourner useState en React.

Par Baptiste Vidal
3 min de lecture
Mis à jour il y a 1 mois
javascriptjsscopeclosureshoistingreact

JavaScript : Portée & closures

Deux concepts qui font peur mais qui sont au cœur du langage. Comprendre la portée et les closures, c'est comprendre pourquoi ton code se comporte comme il le fait, et surtout comment useState fonctionne en React.


# La portée (scope)

La portée, c'est la réponse à la question : « où cette variable est-elle visible ? ». Il y a trois niveaux.

  • Portée globale : déclarée en dehors de toute fonction, accessible partout.
  • Portée de fonction : déclarée dans une fonction, visible uniquement à l'intérieur.
  • Portée de bloc : let et const sont limitées au bloc {} où elles sont déclarées (un if, une boucle for).
let global = "visible partout";
 
function exemple() {
  let locale = "visible seulement dans exemple";
 
  if (true) {
    let bloc = "visible seulement dans ce if";
  }
  // ici, bloc n'existe plus
}

Règle importante : une fonction interne peut lire les variables de la fonction qui l'entoure, mais l'inverse est impossible.


# Le hoisting (en bref)

Avant d'exécuter ton code, JavaScript « remonte » les déclarations en haut de leur portée. En pratique :

  • Une fonction déclarée avec function est utilisable avant sa ligne de définition.
  • let et const sont hoistées elles aussi, mais inutilisables avant leur déclaration : y accéder trop tôt lève une erreur (la zone morte temporelle, ou TDZ).

Retiens simplement : déclare tes variables avant de les utiliser, et tu n'auras jamais de mauvaise surprise.


# Les closures

Une closure, c'est une fonction qui « se souvient » des variables de l'endroit où elle a été créée, même après que cet endroit a fini de s'exécuter. La fonction emporte son environnement avec elle, comme un sac à dos.

function creerCompteur() {
  let compte = 0;              // variable locale à creerCompteur
 
  return function () {
    compte = compte + 1;       // la fonction interne se souvient de "compte"
    return compte;
  };
}
 
const compteur = creerCompteur();
compteur();  // 1
compteur();  // 2
compteur();  // 3

compte n'existe nulle part en dehors de creerCompteur, et pourtant la fonction retournée continue d'y accéder et de le mettre à jour à chaque appel. C'est exactement ça, une closure : une fonction + l'environnement dans lequel elle est née.


# Pourquoi ça compte en React

Les closures sont partout en React, souvent sans qu'on s'en aperçoive :

  • useState repose dessus : à chaque rendu, la fonction du composant « capture » les valeurs de son état à cet instant précis.
  • Un gestionnaire d'événement (onClick={() => ...}) est une closure qui se souvient des props et du state du rendu où il a été créé.

C'est ce qui explique qu'une variable puisse sembler « figée » dans un useEffect ou un callback : elle a été capturée par une closure. On y reviendra avec les hooks.


# À retenir

  • La portée définit où une variable est accessible : globale, de fonction, ou de bloc (let/const dans {}).
  • Le hoisting remonte les déclarations ; déclare avant d'utiliser pour éviter la TDZ.
  • Une closure est une fonction qui garde l'accès aux variables de son environnement de création.
  • Les closures sont le mécanisme qui fait fonctionner useState et les gestionnaires d'événements en React.