Portée en JavaScript : où une variable existe, et où elle n'existe plus

La portée délimite la zone de code où un nom de variable est accessible. Trois niveaux existent en JavaScript, et le bloc est le plus utile.
4 min de lecture
Believemy logo

Une variable n'est pas accessible partout. Le langage délimite pour chaque nom une zone de validité, et en dehors de cette zone, le nom n'existe tout simplement pas.

Cette délimitation n'est pas une contrainte administrative. C'est ce qui permet à deux fonctions écrites par deux personnes différentes d'utiliser toutes les deux une variable total sans jamais se gêner.


Définition

La portée, ou scope, est la région du code dans laquelle un nom déclaré est accessible. JavaScript en distingue trois, de la plus large à la plus étroite.

  • La portée globale : ce qui est déclaré en dehors de toute fonction et de tout bloc. Dans un module, cette portée reste privée au fichier.
  • La portée de fonction : le corps d'une function. C'est la seule que connaît var.
  • La portée de bloc : tout ce qui est entre accolades, y compris un if ou un for. C'est celle de let et const.
JAVASCRIPT
const site = "believemy";        // portée du module

function afficher() {
  const message = "bonjour";     // portée de fonction

  if (message.length > 3) {
    let detail = " !";           // portée de bloc
    console.log(site + " " + message + detail);
  }

  // console.log(detail);        // ReferenceError : hors du bloc
}

afficher(); // believemy bonjour !
La recherche d'un nom remonte les portées et s'arrête au premier trouvéTrois portées emboîtées. Depuis interne(), le nom niveau n'est pas déclaré : la recherche remonte d'un cran, le trouve dans externe() et s'arrête là. La déclaration globale, plus loin, n'est jamais atteinte.Où le moteur trouve-t-il « niveau » ?Portée globaleconst niveau = "global"jamais atteintPortée de externe()const niveau = "externe"trouvé, arrêtPortée de interne()console.log(niveau)rien ici12


La chaîne des portées

Quand le moteur rencontre un nom, il le cherche dans la portée courante, puis dans celle qui l'entoure, et ainsi de suite jusqu'à la portée globale. Le premier trouvé gagne, la recherche s'arrête là.

JAVASCRIPT
const niveau = "global";

function externe() {
  const niveau = "externe";

  function interne() {
    console.log(niveau); // externe, trouvé un cran au-dessus
  }

  interne();
}

externe();
console.log(niveau); // global

La recherche ne va que vers l'extérieur, jamais vers l'intérieur : depuis externe, la variable déclarée dans interne est invisible. C'est cette chaîne, capturée par une fonction, qui donne une Closure (fermeture).

Bon à savoir

Déclarer un nom déjà pris dans une portée englobante le masque à l'intérieur, sans toucher à l'original. Utile, mais source de confusion quand les deux variables représentent des choses différentes.


Ce que ça change au quotidien

  • Déclarez au plus près de l'usage. Une variable visible sur trois lignes se relit sans effort.
  • Évitez la portée globale. Un nom global est modifiable par n'importe quel code du programme.
  • Méfiez-vous d'un var dans un bloc. Il en sort et reste visible dans toute la fonction.
  • Un fichier de module est déjà une portée. Rien n'en sort sans un export explicite.


Questions fréquentes

Question

Une variable oubliée dans une déclaration devient-elle globale ?

Dans un script classique, oui : écrire total = 5 sans mot-clé crée une propriété globale, accessible depuis tout le programme. C'est l'un des accidents les plus coûteux du langage. En mode strict, et donc dans tout module, la même ligne lève une erreur, ce qui est nettement préférable.


Question

Quelle différence entre portée et Hoisting (remontée) ?

La portée répond à la question « où ce nom est-il accessible », le hoisting à la question « à partir de quand ». Les deux se combinent : une variable let a la portée de son bloc, et à l'intérieur de ce bloc elle reste illisible tant que sa ligne de déclaration n'a pas été exécutée.


Question

Une portée disparaît-elle vraiment à la fin du bloc ?

En général oui, la mémoire est récupérée. Sauf si une fonction déclarée à l'intérieur est encore référencée ailleurs : elle maintient alors en vie les variables qu'elle utilise. C'est précisément le mécanisme des closures, et la raison pour laquelle un compteur peut retenir sa valeur entre deux appels.

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.