
JavaScript : Qu'est ce que le hoisting ?
#1
En JavaScript on peut appeler une fonction avant de l'avoir déclarée
C'est assez surprenant mais c'est la réalité. Evidemment il y a une raison à cela. Vous avez déjà dû le constater mais je vais faire un exemple pour le vérifier.
Ci-dessous j'appelle la fonction afficheResultats
alors qu'elle n'est pas encore déclarée et pourtant tout se passe bien. Je déclare aussi une variable x
que j'initialise à 0
. Nous verrons plus loin pourquoi je fais ça.
#2
Expliquer ce fonctionnement par le hoisting
Pour expliquer ce fonctionnement une explication existe : le hoisting (hissage en français). Le raisonnement consiste à dire que toutes les déclarations aussi bien de variables que de fonctions sont hissées vers le haut de leur espace de portée.
Ainsi la fonction pourrait être appelée avant d'être déclarée puisque déplacée vers le haut de la portée globale par le moteur JavaScript.
Il se trouve que c'est une explication qui est donnée disons pour "faire simple" mais qu'en réalité aucune instruction n'est déplacée.
#3
Ce qui se passe en réalité
La vraie explication me parait beaucoup plus simple. En fait le moteur JavaScript analyse deux fois le code :
- Dans la première analyse il s'intéresse aux déclarations. Il les mémorise.
- Dans la deuxième analyse il va procéder à l'exécution.
Il me semble que l'on comprend facilement que dans ces conditions le moteur JavaScript puisse exécuter une fonction lors d'une deuxième analyse alors qu'il l'a identifiée cette même fonction dans une première analyse.
La conséquence c'est que l'ordre d'exécution des instructions se trouve modifié. La déclaration de la fonction afficheResultat
(* ligne 12 à 14) va être prise en compte avant l'exécution de la fonction (* ligne 10).
Dans ces conditions on comprend qu'on puisse interpréter cette situation comme un déplacement des instructions. Mais il faut s'empresser de donner l'explication car si les instructions se déplacent dans le code c'est pour le moins troublant.
Alors c'est intéressant de regarder ce qui se passe au niveau de la déclaration de la variable let x=0
. Dans la première analyse le moteur va s'intéresser au let x
et dans la deuxième analyse il va s'intéresser au x=0
. Donc une instruction de ce type est exécutée en deux temps. Elle est en quelque sorte coupée en deux et une moitié est déplacée. Surprenant non !
Pour être précis je dois ajouter que chaque déclaration est rangée dans son espace de portée. Les déclarations lues dans l'espace global seront "rangées en haut" de l'espace global. Celles lues dans une fonction seront "rangées en haut" dans la fonction. Celles lues dans un bloc seront "rangées en haut" du bloc.
#4
On fait un exemple
- Je déclare une variable globale
test
et je l'initialise à la chaîne'globale'
. - Je déclare une fonction
func
dans laquelle je fais unconsole.log(test)
. - Je déclarer à nouveau une variable
test
que j'initialise à la chaîne'locale'
. - J'invoque la fonction.
Maintenant je pose la question : que va afficher le concole.log
de test
?

On va raisonner avec le hoisting pour expliquer cette réponse :
- La deuxième déclaration de la variable
test
est coupée en deux. - La déclaration
var test
est hissée en haut de la fonction. Elle masque la première déclaration de la variabletest
initialisée à'globale'
. - L'initialisation de
test='locale'
ne bouge pas. - Le
console.log
affiche doncundefined
.
Tout se passe comme si on exécutait le code ci-dessous :
Il faut remarquer que j'ai utilisé exceptionnellement des var
pour mes déclarations de variables de manière à produire cette situation un petit peu tordue. Avec des let
c'est une exception qui serait levée.
En conclusion : le meilleur moyen de ne pas avoir recours au hoisting c'est d'écrire son code proprement et de déclarer ses variables en haut des différentes portée, d'utiliser des let
ou des const
, d'utiliser le mode strict.