Le Scope ou la portée des variables

Définition d’un scope

Le scope est un des concepts clés de Javascript.

La portée ou scope, désigne l’accessibilité des variables, autrement dit : Où et quand une variable peut être utilisée par votre programme.

Nous désignons 3 types de scope :

  • Le Global Scope

Global Scope
1// GLOBAL SCOPE
2var animal = "Elephant";
3var population = 10;

Les variables sont déclarées dans le script en dehors d’un bloc d’instruction ou d’une fonction.

  • Le Local Scope

Function (local) Scope
1// FUNCTION SCOPE
2function zoo() {
3  var animal = "Tigre";
4  var population = 5;
5  console.log(animal, population);
6}

Les variables sont déclarées dans le corps de la fonction zoo.

  • Le Block Scope, dans un bloc d’instruction(if, else, while, for .. ).

Block scope
1// BLOCK SCOPE
2for(var population = 0; population <10 ; population++) {
3  console.log(animal, population);
4}

La variable population est déclarée dans le block déclaratif de la boucle for.

Etude de la portée des variables

Lisez le code suivant :

1var var1 = 10;
2console.log(var1);

var1 est déclaré dans le global scope. Nous pouvons afficher sa valeur sans problème avec un console.log.

Ajoutons maintenant un block conditionnel et tentons d’accèder depuis ce block à notre variable var1.

1var var1 = 10;
2console.log(`Global Scope 1 : ${var1}`);
3if(true) {
4  console.log(`Block Scope 1 : ${var1}`);
5  var1++;
6  console.log(`Block Scope 2 : ${var1}`);
7}
8console.log(`Global Scope 2 : ${var1}`);

La console retourne :

"Global Scope 1 : 10"
"Block Scope 1 : 10"
"Block Scope 2 : 11"
"Global Scope 2 : 11"

Observation 1

Une variable déclarée dans le Global Scope peut être lue et modifiée dans le Block Scope.

Déclarons maintenant une variable var2 dans le Block et tentons d’y accèder depuis l’extérieur.

1if(true) {
2  var var1 = 10;
3}
4console.log(`Global Scope 1 : ${var1}`);

La console retourne :

"Global Scope 1 : 10"

Observation 2

Une variable déclarée dans le Block Scope peut être lue et modifiée dans le Global Scope.

Maintenant déclarons une fonction increment:

1var var1 = 10;
2function increment() {
3  var1++;
4}
5increment();
6console.log(`Global Scope 1 : ${var1}`);

La console retourne :

"Global Scope 1 : 11"

Observation 3

Une variable déclarée dans le Global Scope peut être lue et modifiée dans le Function Scope. C’est ce que l’on appelle un effet de bord ou side effect.

Avertissement

Attention aux effets de bord des fonctions que vous écrivez dans vos scripts. Ils peuvent complexifier leur lecture et leur débogage. Car une variable déclarée dans le Global Scope pourrait être modifiée par de nombreuses fonctions à effets de bord rendant difficile la prévision des valeurs durant le cycle de vie de votre script.

Déclarons une nouvelle variable dans le corps de la fonction.

1var var1 = 10;
2function increment() {
3  var var2 = 20;
4  var1++;
5}
6increment();
7console.log(`Global Scope 1 : ${var2}`);

La console retourne :

"Uncaught ReferenceError: var2 is not defined"

Observation 4

Une variable déclarée dans le Function Scope ne peut être lue et modifiée dans le Global Scope.

Prenons un nouveau cas de figure :

Nous déclarons var1 dans le Global Scope puis nous déclarons une nouvelle variable avec le même nom var1 dans un Block Scope.

1var var1 = 10;
2console.log(`Global Scope 1 : ${var1}`);
3if(true) {
4  var var1 = 100;
5  console.log(`Function Scope 1 : ${var1}`);
6}
7console.log(`Global Scope 2 : ${var1}`);

La console retourne :

"Global Scope 1 : 10"
"Function Scope 1 : 100"
"Global Scope 2 : 100"

Observation 5

Il n’existe pas de portée de Block pour les variables var.

La version ECMAScript2015 a introduit dans Javascript deux nouveaux mots clés : let et const. let permet de pallier au problème soulevé dans l”Observation 5. Reprenons le code précédent et remplaçons maintenant var par let.

1let var1 = 10;
2console.log(`Global Scope 1 : ${var1}`);
3if(true) {
4  let var1 = 100;
5  console.log(`Function Scope 1 : ${var1}`);
6}
7console.log(`Global Scope 2 : ${var1}`);

La console retourne :

"Global Scope 1 : 10"
"Function Scope 1 : 100"
"Global Scope 2 : 10"

Observation 6

Les variables créées avec le mot clé let appartiennent au scope dans lequel elles ont été définies. Toutefois, elles restent accessible et modifiable dans les blocks enfants.

let var1 = 10;
console.log(`Global Scope 1 : ${var1}`);
if(true) {
  var1 = 100;
  console.log(`Function Scope 1 : ${var1}`);
}
console.log(`Global Scope 2 : ${var1}`);

Note

Il faut donc privilégier l’utilisation du mot clé let au lieu de var afin d’éviter des désagréments.

Le mot clé const sert à déclarer une référence constante. Attention, une référence constante ne veut pas dire que la valeur derrière la référence est « immutable », mais que la référence elle-même est immutable.

1const a = 10;
2a++;

Nous essayons de modifier la valeur de a déclaré pourtant comme étant une constante const. Cela est interdit.

Toutefois :

1const a = {txt: "hello"}; //Référence r0 vers l'objet
2const b = a; //Référence r0 vers le même objet
3a.txt += " world" //Adresse 0x0002
4console.log(a); //"hello world";
5console.log(b); //"hello world";

Ici, a est de type complexe, c’est un objet. Ce n’est pas sa valeur qui est stockée dans la variable mais une référence de l’objet, l’adresse mémoire qu’il occupe. Ainsi, un objet peut être déclaré avec le mot clé const et se voir ajouter, modifier, supprimer des éléments.

Nous n’allons pas tester toutes les scopes avec const.

Voici un tableau comparatif :

../../../_images/img1.png

Exercice

Exercice 1 : Modifier le script pour que la console retourne la valeur 10.
1var i = 10;
2for(var i =0;i<=5;i++) {
3  // Do Stuff
4}
5console.log(i)