Différences de var, let et const | Hissage (Hoisting) et Portée (Scope)

Pourquoi est-ce qu'il y a autant de mots-clés de déclaration de variables en JavaScript ? Jetons un coup d'œil à chacun, et plongeons également dans les concepts de hissage (hoisting) et de portée (scope).

Keywords: JavaScript, tutoriel, hoist, scope, hissage, portée

By Carmen Cincotti  

Que vous soyez un développeur JavaScript débutant ou un expert cherchant à vraiment apprendre les subtilités du langage, une question peut vous perturber :

var, let, const - quelles sont les différences entre ces trois mots-clés en JavaScript ?

Confused woman

Certains développeurs JavaScript s’en tiennent à une règle d’or pour utiliser const à moins qu’une variable ne doive être réaffectée à l’avenir. Dans ce cas, ils utilisent let.

Cependant, parfois ce n’est pas toujours le cas, et vous pouvez rencontrer du code qui n’utilise que var.

Commençons !

La portée (ou en anglais - scope)

Pour commencer notre enquête sur le monde de la syntaxe JS, nous devons d’abord en savoir plus sur la portée (ou en anglais - scope).

La portée définit l’accessibilité des variables pendant la durée de vie d’un programme. En ce qui concerne JavaScript, il existe une portée globale, une portée de fonction et une portée de bloc :

  • Portée globale - la portée accessible n’importe où tout au long du programme.
  • Portée de la fonction - la portée au sein d’une définition de fonction.
  • Portée du bloc - la portée entre { } comme dans le corps d’une boucle for.

Prenons l’exemple suivant :

// La portée globale const globalScopeVariable = "global" function laPortéeDeLaFonction() { const functionScopeVariable = "function" // La portée du bloc { const blockScopeVariable = "block" // on peut accéder à globalScopeVariable, à functionScopeVariable et à blockScopeVariable } // on peut accéder à globalScopeVariable, et à functionScopeVariable } // on peut accéder à globalScopeVariable

Comme nous pouvons le voir, la portée contrôle l’accessibilité de certaines variables. Nous disons qu’une certaine variable est limitée (ou en anglais - “scoped”) à un certain type de portée (c’est-à-dire que blockScopeVariable est limitée à la portée au bloc dans lequel elle se trouve).

La relation entre l’accessibilité des variables et la portée peut fonctionner un peu comme une poupée russe.

Picture of Russian doll

Par exemple, la portée globale encapsule à la fois la portée de la fonction et celle du bloc. La fonction et la portée du bloc fonctionnent de manière quelque peu interchangeable. Par exemple - c’est parfaitement OK pour écrire le programme suivant :

function scopeOne() { { function scopeTwo() { { let high = "five" } } } }

Comme vous pouvez le voir - la fonction scopeTwo est définie dans un bloc

Maintenant que nous comprenons la portée, examinons les différences entre var et let.

var ou let - Hoisting (Hissage)

Commençons par définir deux variables. L’un avec le mot-clé let et l’autre avec le mot-clé var :

let myLet = "Pomme" var myVar = "Orange" console.log({ myLet, myVar }) // SORTIE: { myLet: 'Pomme', myVar: 'Orange' } // **Protip** - l'enregistrement des variables en tant qu'objet augmente la lisibilité, car les paires clé-valeur sont enregistrées dans la console.

Créons maintenant une fonction. En faisant cela, nous montrerons une différence clé en enregistrant ces deux variables sur la console avant qu’elles soient définies.

function myFunction() { console.log({myVar}) console.log({myLet}) let myLet = "Pomme" var myVar = "Orange" } myFunction();

L’exécution de ceci nous donne l’erreur suivante :

{ myVar: undefined } Thrown: ReferenceError: myLet Cannot access 'myLet' before initialization at myFunction

…Quoi ? 🤔 myVar est undefined et myLet renvoie une ReferenceError indiquant que myLet n’a pas encore été défini.

Que se passe-t-il ici ?

myVar est hissé (hoisted) au sommet de la portée de la fonction, et est donc considéré comme accessible tout au long de la fonction même avant qu’il ne soit défini avec une valeur appropriée. En fait, il prend la valeur de undefined (pas défini).

Avant de continuer, examinons comment notre code JavaScript est construit et exécuté, et à partir de là, nous comprendrons mieux ce concept de hissage (hoisting).

Création et exécution de code JavaScript

Lors de l’interprétation du code JavaScript, il y a 2 phases.

⚠️ Ceci est une généralisation. Chaque moteur JS est différent.

  1. La phase de création correspond au moment où l’interpréteur JavaScript alloue de l’espace pour les déclarations de variables et de fonctions en mémoire.
  2. La phase d’exécution correspond au moment où l’interpréteur JavaScript commence à exécuter notre code ligne par ligne.

Alors, que s’est-il exactement passé pendant “la phase de création” dans l’extrait d’exemple ci-dessus ? myVar a été défini avec une valeur par défaut de undefined.

myLet est différent. Il est alloué de la mémoire, et donc techniquement hoisted (hissé) mais il est considéré comme étant dans un état appelé zone morte temporelle (temporal dead zone). Dans cet état, myLet se voit allouer de la mémoire, mais elle est techniquement inaccessible.

Donc, pour résumer notre première différence entre let et var :

var peut être accédé et écrasé n’importe où dans une portée de fonction ou une portée globale en raison du hissage (hoisting). let présente également ce comportement, sauf qu’il n’est pas accessible, car il se trouve dans un état nommé zone morte temporelle (temporal dead zone).

var vs let - Différences de portée

Une autre différence est le comportement de let et var en ce qui concerne la portée. Jetons un œil à cet exemple :

var myVar = "FirstVar" let myLet = "FirstLet" function myFunction() { console.log({myVar}) console.log({myLet}) { console.log({myVar}) console.log({myLet}) var myVar = "SecondVar" let myLet = "SecondLet" } } myFunction();

Ce qui nous renvoie ceci :

{ myVar: undefined } { myLet: 'FirstLet' } { myVar: undefined } Uncaught ReferenceError: Cannot access 'myLet' before initialization at myFunction

…Hein ? 🤔 myVar est undefined et myLet est FirstLet ?

Il semble que myLet ait hérité de la valeur FirstLet de la portée globale et qu’il soit devenu inaccessible lorsqu’il a été réassigné dans ce bloc.

Ce n’est peut-être pas évident, mais la différence que nous voyons ici est que la variable définie par var, myVar, est hissée dans la définition de fonction la plus proche de laquelle elle réside, tandis que let ne le fait pas . let est hissé au bloc le plus proche.

C’est pourquoi on nous renvoie que myLet est inaccessible dans la portée du bloc, mais pas dans la portée de la fonction !

Pour résumer : var est limité - ou “scoped” - à la fonction et let est limité au bloc !

Résumé de let/const vs var

Donc, en résumé, les deux principales différences entre let (ainsi que const) et var sont :

  1. Comment chacun est initialisé dans la ‘phase de création’
  • var est initialisé avec undefined
  • let/const sont initialisés en tant que zones mortes temporelles (temporal dead zones) et sont donc considérés comme non accessibles tant qu’ils ne sont pas définis dans la phase d’exécution.
  1. Comment chacun est défini par rapport à la portée
  • var est limité à la fonction.
  • let/const sont limités au bloc.

Bonus : un mot supplémentaire sur le hissage

Les fonctions peuvent également être hissées. Prenons cet exemple :

catName("Chloe"); function catName(name) { console.log("My cat's name is " + name); } // SORTIE: "My cat's name is Chloe"

Cette déclaration de function n’est pas comme ce que nous avons vu avec var où elle renvoie undefined. En fait, elle est techniquement accessible lorsqu’on l’appelle avant dans le code !

Dans tous les cas, si vous trouvez que c’est ennuyeux - vous pouvez ajouter strict mode en haut de votre code JavaScript pour désactiver complètement le hissage :

'use strict';

Des ressources (en français et anglais)


Comments for Différences de var, let et const | Hissage (Hoisting) et Portée (Scope)



Written by Carmen Cincotti, computer graphics enthusiast, language learner, and improv actor currently living in San Francisco, CA.  Follow @CarmenCincotti

Contribute

Interested in contributing to Carmen's Graphics Blog? Click here for details!