open

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 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 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éclarer à 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 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.