Hoisting (remontée)
En JavaScript, l'anglicisme hoisting, qu'on peut traduire en « remontée » (voire plus littéralement en « hissage ») correspond au déplacement de la déclaration de fonctions, variables ou classes en haut de leur portée avant l'exécution du code.
Le hissage/la remontée n'est pas un terme défini de façon normative dans la spécification ECMAScript. La spécification définit un groupe de déclarations comme HoistableDeclaration, mais cela inclut uniquement les déclarations function
, function*
, async function
, et async function*
. La remontée est souvent associée aux déclarations var
d'une façon légèrement différente. Généralement, on regroupe les différents comportements suivants sous ce terme :
- Être capable d'utiliser la valeur d'une variable dans sa portée avant la ligne où elle est déclarée (« remontée de variable »)
- Être capable de référence une variable dans sa portée avant la ligne où elle est déclarée, sans que cela déclenche une exception
ReferenceError
, mais où la valeur obtenue estundefined
(« remontée de déclaration ») - La déclaration de la variable entraîne des changements de comportement dans la portée avant la ligne où elle est déclarée.
Les déclarations sans mot-clé préalable sont remontées selon le premier comportement. Les déclarations avec var
sont remontées selon le deuxième comportement. Enfin, les déclarations avec let
, const
, et class
(parfois désignées comme déclarations lexicales) sont remontées selon le troisième comportement.
On peut également considérer que let
, const
, et class
ne déclenchent pas de remontée en raison de la zone morte temporaire qui interdit toute utilisation de la variable avant sa déclaration. Cette différence d'interprétation est acceptable, car le terme n'est pas précisément normé dans la spécification. Toutefois, la zone morte temporaire peut entraîner d'autres modifications observables dans la portée, suggérant ainsi une certaine forme de remontée :
const x = 1;
{
console.log(x); // ReferenceError
const x = 2;
}
Si la déclaration const x = 2
n'était pas remontée du tout (autrement si le seul effet produit avait lieu lors de l'exécution), l'instruction console.log(x)
devrait être capable de lire la valeur de x
de la portée parente. Toutefois, la déclaration const
touche quand même la portée dans laquelle elle est définie et l'instruction console.log(x)
lit la valeur du x
provenant de la déclaration const x = 2
, qui n'est pas encore initialisé et déclenche donc une exception ReferenceError
. Cela étant écrit, on peut considérer l'absence de remontée comme l'absence d'effet de bord utile.
On notera que ce qui suit n'est pas une forme de remontée :
{
var x = 1;
}
console.log(x); // 1
Comme la portée des déclarations var
n'est pas limitée aux blocs, il n'y a pas d'accès avant déclaration ici.
Pour plus d'informations à ce sujet, voir :
- La remontée pour
var
/let
/const
dans le guide sur la grammaire et les types en JavaScript - La remontée pour
function
dans le guide sur les fonctions - La remontée pour
class
dans le guide sur les classes