close

JavaScript : Qu'est ce que le hoisting ?

#1 En JavaScript on peut appeler une fonction avant de l'avoir déclarée open

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.

Tester le code

#2 Expliquer ce fonctionnement par le hoisting open

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é open

La vraie explication me parait beaucoup plus simple. En fait, le moteur JavaScript analyse deux fois le code :

  1. Dans la première analyse, il s'intéresse aux déclarations. Il les mémorise.
  2. 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. 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 open

  1. Je déclare une variable globale test et je l'initialise à la chaîne 'globale'.
  2. Je déclare une fonction func dans laquelle je fais un console.log(test).
  3. Je déclare à nouveau une variable test que j'initialise à la chaîne 'locale'.
  4. J'invoque la fonction.

Maintenant, je pose la question : que va afficher le concole.log de test ?

Tester le code
Exemple de hoisting

On va raisonner avec le hoisting pour expliquer cette réponse :

  1. La deuxième déclaration de la variable test est coupée en deux.
  2. La déclaration var test est hissée en haut de la fonction. Elle masque la première déclaration de la variable test initialisée à 'globale'.
  3. L'initialisation de test='locale' ne bouge pas.
  4. Le console.log affiche donc undefined.

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 à se préoccuper du hoisting c'est d'écrire son code proprement et de déclarer ses variables en haut des différentes portées, d'utiliser des let ou des const, d'utiliser le mode strict.