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.
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 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à.
const niveau = "global";
function externe() {
const niveau = "externe";
function interne() {
console.log(niveau); // externe, trouvé un cran au-dessus
}
interne();
}
externe();
console.log(niveau); // globalLa 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).
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
vardans 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
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.
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.
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.