Var, let ou const? Problèmes de portée variable et ES6

Les étendues en JavaScript ont toujours été un sujet délicat, en particulier par rapport aux langages plus strictement organisés tels que C et Java. Pendant de nombreuses années, la portée de JS n'a pas été particulièrement discutée, car le langage n'avait tout simplement aucun moyen susceptible d'affecter de manière significative la situation actuelle. Mais dans ECMAScript 6, il existe de nouvelles fonctionnalités qui permettent aux développeurs de mieux contrôler la portée des variables. Ces fonctionnalités sont désormais très bien supportées par les navigateurs, elles sont assez accessibles à la plupart des développeurs. Cependant, de nouveaux mots-clés pour déclarer des variables, tenant compte du fait que l'ancien mot-clé var n'a pas disparu, signifient non seulement de nouvelles opportunités, mais aussi l'apparition de nouvelles questions. Quand utiliser les mots clés let et const ? Comment se comportent-ils? Dans quelles situations le mot-clé var -il toujours pertinent? Le matériel, dont nous publions la traduction aujourd'hui, vise à explorer le problème de la portée des variables en JavaScript.



Portées variables: un aperçu


La portée d'une variable est un concept important en programmation, ce qui peut toutefois dérouter certains développeurs, en particulier les novices. La portée d'une variable est la partie du programme dans laquelle cette variable est accessible.

Jetez un œil à l'exemple suivant:

 var myVar = 1; function setMyVar() { myVar = 2; } setMyVar(); console.log(myVar); 

Que produira la méthode console.log ? La réponse à cette question ne surprendra personne: elle affichera 2 . La variable myVar déclarée en dehors d'une fonction, ce qui nous indique qu'elle est déclarée dans la portée globale. Par conséquent, toute fonction déclarée dans la même portée pourra accéder à myVar . En effet, lorsqu'il s'agit de code exécuté dans un navigateur, même les fonctions déclarées dans d'autres fichiers connectés à la page auront accès à cette variable.

Jetez maintenant un œil au code suivant:

 function setMyVar() { var myVar = 2; } setMyVar(); console.log(myVar); 

Extérieurement, ses changements, par rapport à l'exemple précédent, sont insignifiants. À savoir, nous venons de mettre la déclaration de variable à l'intérieur de la fonction. Que produira console.log maintenant? En fait, rien, puisque cette variable n'est pas déclarée et lorsque vous essayez d'y accéder, un message concernant une erreur ReferenceError non gérée sera affiché. Cela s'est produit parce que la variable a été déclarée dans la fonction à l'aide du mot clé var . Par conséquent, la portée de cette variable est limitée à la portée interne de la fonction. Elle est accessible dans le corps de cette fonction, les fonctions intégrées à cette fonction peuvent fonctionner avec elle, mais elle n'est pas accessible de l'extérieur. Si nous avons besoin de plusieurs fonctions au même niveau pour utiliser une certaine variable, nous devons déclarer cette variable au même endroit où ces fonctions sont déclarées, c'est-à-dire un niveau supérieur à leur portée interne.

Voici une observation intéressante: le code de la plupart des sites Web et des applications Web ne s'applique pas au travail d'un seul programmeur. La plupart des projets logiciels sont le résultat du développement d'une équipe et, en outre, ils utilisent des bibliothèques et des frameworks tiers. Même si un seul programmeur est impliqué dans le développement d'un site Web, il utilise généralement des ressources externes. Pour cette raison, il n'est généralement pas recommandé de déclarer des variables dans la portée globale, car vous ne pouvez pas savoir à l'avance quelles variables seront déclarées par d'autres développeurs dont le code sera utilisé dans le projet. Pour contourner ce problème, vous pouvez utiliser certaines astuces, en particulier le modèle « Module » et IIFE lors de l'application de l'approche orientée objet au développement JavaScript, bien que l'encapsulation de données et de fonctions dans des objets ordinaires puisse obtenir le même effet. En général, on peut noter que les variables dont la portée dépasse ce dont elles ont besoin sont généralement un problème avec lequel quelque chose doit être fait.

Problème de mot clé var


Nous avons donc compris le concept de «portée». Passons maintenant à des choses plus complexes. Jetez un œil au code suivant:

 function varTest() { for (var i = 0; i < 3; i++) {   console.log(i); } console.log(i); } varTest(); 

Qu'est-ce qui arrivera à la console après son exécution? Il est clair que les valeurs du compteur croissant i : 0 , 1 et 2 seront affichées à l'intérieur de la boucle. Une fois la boucle terminée, le programme continue de s'exécuter. Maintenant, nous essayons d'accéder à la même variable de compteur qui a été déclarée dans la boucle for , en dehors de cette boucle. Que va-t-il en résulter?

Après avoir appelé i dehors de la boucle, 3 entrera dans la console, car le mot-clé var agit au niveau de la fonction. Si vous déclarez une variable à l'aide de var , vous pouvez y accéder dans une fonction même après avoir quitté la construction où elle a été déclarée.

Cela peut devenir un problème lorsque les fonctions deviennent plus complexes. Prenons l'exemple suivant:

 function doSomething() { var myVar = 1; if (true) {   var myVar = 2;   console.log(myVar); } console.log(myVar); } doSomething(); 

Qu'est-ce qui va arriver à la console maintenant? 2 et 2 . Nous déclarons une variable, l'initialisons avec le chiffre 1, puis essayons de redéfinir la même variable à l'intérieur de l' if . Étant donné que ces deux déclarations existent dans la même portée, nous ne pouvons pas déclarer une nouvelle variable avec le même nom, même si nous voulons évidemment le faire. Par conséquent, la première variable est remplacée à l'intérieur de l' if .

C'est précisément le plus gros défaut du mot-clé var . La portée des variables déclarées en l'utilisant est trop grande. Cela peut entraîner un écrasement accidentel des données et d'autres erreurs. De vastes zones de visibilité conduisent souvent à des programmes inexacts. En général, une variable doit avoir une portée limitée par ses besoins, mais ne les dépassant pas. Ce serait bien de pouvoir déclarer des variables dont la portée n'est pas aussi grande que lors de l'utilisation de var , ce qui permettrait, si nécessaire, d'utiliser des constructions logicielles plus stables et plus résistantes aux erreurs. En fait, ECMAScript 6 nous offre de telles opportunités.

Nouvelles façons de déclarer des variables


La norme ECMAScript 6 (un nouvel ensemble de fonctionnalités JavaScript, également connu sous le nom ES6 et ES2015) nous donne deux nouvelles façons de déclarer des variables qui diffèrent dans leur portée, par rapport à var , et qui ont d'autres fonctionnalités. Ce sont les mots clés let et const . Les deux nous donnent la soi-disant portée de bloc. Cela signifie que la portée de leur utilisation peut être limitée à un bloc de code, comme une boucle for ou une if . Cela donne au développeur plus de flexibilité dans le choix de la portée des variables. Considérez les nouveaux mots clés.

▍Utilisation du mot clé let


Le mot clé let est très similaire à var , la principale différence est la portée limitée des variables déclarées avec lui. Nous réécrivons l'un des exemples ci-dessus, en remplaçant var par let :

 function doSomething() { let myVar = 1; if (true) {   let myVar = 2;   console.log(myVar); } console.log(myVar); } doSomething(); 

Dans ce cas, les chiffres 2 et 1 arriveront à la console. Cela se produit car l' if définit une nouvelle portée pour la variable déclarée avec le mot clé let . Cela conduit au fait que la deuxième variable déclarée est une entité complètement indépendante, non liée à la première. Vous pouvez travailler avec eux indépendamment les uns des autres. Cependant, cela ne signifie pas que les blocs de code imbriqués, tels que notre if , sont complètement coupés des variables déclarées avec le mot clé let dans la portée dans laquelle ils se trouvent. Jetez un œil au code suivant:

 function doSomething() { let myVar = 1; if (true) {   console.log(myVar); } } doSomething(); 

Dans cet exemple, la console obtiendra le numéro 1 . Le code à l'intérieur de l' if a accès à la variable que nous avons créée en dehors d'elle. Par conséquent, il affiche sa valeur dans la console. Et que se passe-t-il si vous essayez de mélanger la portée? Par exemple, procédez comme suit:

 function doSomething() { let myVar = 1; if (true) {   console.log(myVar);   let myVar = 2;   console.log(myVar); } } doSomething(); 

Il peut sembler que le premier appel à console.log produira 1 , mais en fait, lorsque vous essayez d'exécuter ce code, une erreur ReferenceError apparaîtra qui nous indique que la variable myVar pour cette étendue n'est pas définie ou non initialisée (le texte de cette erreur diffère selon les différents navigateurs). En JavaScript, il existe une telle chose que d'élever des variables au sommet de leur portée. Autrement dit, si une variable est déclarée dans une certaine portée, JavaScript lui réserve une place avant même que la commande pour la déclarer ne soit exécutée. La manière exacte dont cela se produit diffère lorsque vous utilisez var et let .

Prenons l'exemple suivant:

 console.log(varTest); var varTest = 1; console.log(letTest); let letTest = 2; 

Dans les deux cas, nous essayons d'utiliser la variable avant de la déclarer. Mais les commandes de sortie de la console se comportent différemment. La première, à l'aide d'une variable qui sera déclarée ultérieurement à l'aide du mot clé var , affichera undefined - c'est-à-dire ce qui sera écrit dans cette variable. La deuxième commande, qui essaie d'accéder à la variable, qui sera déclarée plus tard à l'aide du mot clé let , lancera une ReferenceError et nous dira que nous essayons d'utiliser la variable avant qu'elle ne soit déclarée ou initialisée. Quel est le problème?

Et la chose ici est qu'avant l'exécution du code, les mécanismes responsables de son exécution regardent ce code, découvrent si des variables y seront déclarées et, si c'est le cas, les augmentent en réservant de la place pour elles. Dans ce cas, les variables déclarées à l'aide du mot clé var sont initialisées à undefined dans leur portée, même si elles sont accessibles avant d'être déclarées. Le principal problème ici est que la valeur undefined dans une variable n'indique pas toujours qu'ils essaient d'utiliser la variable avant sa déclaration. Jetez un œil à l'exemple suivant:

 var var1; console.log(var1); console.log(var2); var var2 = 1; 

Dans ce cas, bien que var1 et var2 déclarés différemment, les deux appels à console.log sortiront undefined . Le point ici est que dans les variables déclarées avec var , mais non initialisées, la valeur undefined automatiquement écrite. En même temps, comme nous l'avons déjà dit, les variables déclarées à l'aide de var , auxquelles on accède avant de les déclarer, contiennent également undefined . Par conséquent, si quelque chose se passe mal dans un tel code, il ne sera pas possible de comprendre quelle est exactement la source de l'erreur - en utilisant une variable non initialisée ou en utilisant une variable avant sa déclaration.

La place des variables déclarées avec le mot let clé let est réservée dans leur bloc, mais avant de les déclarer, elles tombent dans la zone morte temporaire (TDZ, Temporal Dead Zone). Cela conduit au fait qu'ils ne peuvent pas être utilisés avant d'être déclarés, et une tentative d'accès à une telle variable entraîne une erreur. Cependant, le système connaît exactement la cause du problème et le signale. Cela se voit clairement dans cet exemple:

 let var1; console.log(var1); console.log(var2); let var2 = 1; 

Ici, le premier appel à console.log sortira undefined , et le second lancera une erreur ReferenceError , nous indiquant que la variable n'a pas encore été déclarée ou initialisée.

Par conséquent, si l'utilisation de var semble undefined , nous ne connaissons pas la raison de ce comportement du programme. Une variable peut être déclarée et non initialisée, ou elle ne peut pas encore être déclarée dans cette étendue, mais elle sera déclarée dans le code situé sous la commande pour y accéder. En utilisant le mot clé let , nous pouvons comprendre ce qui se passe exactement, ce qui est beaucoup plus utile pour le débogage.

▍Utilisation du mot-clé const


Le mot clé const est très similaire à let , mais ils ont une différence importante. Ce mot-clé est utilisé pour déclarer des constantes. Les valeurs des constantes ne peuvent pas être modifiées après leur initialisation. Il convient de noter que cela ne s'applique qu'aux valeurs des types primitifs, de l'eau, des chaînes ou des nombres. Si la constante est quelque chose de plus complexe, par exemple, un objet ou un tableau, la structure interne d'une telle entité peut être modifiée, vous ne pouvez pas simplement la remplacer par une autre. Jetez un œil au code suivant:

 let mutableVar = 1; const immutableVar = 2; mutableVar = 3; immutableVar = 4; 

Ce code sera exécuté jusqu'à la dernière ligne. Tenter d'attribuer une nouvelle valeur à une constante entraînera une erreur TypeError . C'est ainsi que se comportent les constantes, mais, comme déjà mentionné, les objets que les constantes initialisent peuvent être modifiés, ils peuvent subir des mutations, ce qui peut entraîner des surprises .

Peut-être qu'en tant que développeur JavaScript, vous vous demandez pourquoi l'immunité des variables est importante. Les constantes sont un nouveau phénomène en JavaScript, alors qu'elles sont une partie essentielle de langages comme C ou Java. Pourquoi ce concept est-il si populaire? Le fait est que l'utilisation de constantes nous fait réfléchir au fonctionnement de notre code. Dans certaines situations, la modification de la valeur d'une variable peut perturber le code, par exemple, si le nombre Pi y est écrit et qu'il est constamment consulté, ou si la variable a un lien vers un élément HTML avec lequel vous devez travailler en permanence. Disons, voici une constante dans laquelle un lien vers un certain bouton est écrit:

 const myButton = document.querySelector('#my-button'); 

Si le code dépend du lien vers l'élément HTML, alors nous devons garantir l'immuabilité de ce lien. Par conséquent, nous pouvons dire que le mot clé const suit non seulement le chemin des améliorations dans le domaine de la visibilité, mais également le chemin de la limitation de la possibilité de modifier les valeurs des constantes déclarées à l'aide de ce mot clé. Rappelez-vous comment nous avons dit qu'une variable devrait avoir exactement la portée dont elle a besoin. Cette idée peut être poursuivie en proposant une recommandation, selon laquelle une variable ne devrait avoir que la capacité de changer, ce qui est nécessaire pour un bon travail avec elle, et rien de plus. Voici un bon matériel sur le thème de l'immunité, dont une conclusion importante peut être tirée, selon laquelle l'utilisation de variables immuables nous fait réfléchir soigneusement à notre code, ce qui conduit à une amélioration de la pureté du code et à une réduction du nombre de mauvaises surprises qui surviennent lors de son fonctionnement.

Lorsque j'ai commencé à utiliser les mots clés let et const , j'ai essentiellement utilisé let , le recours à const uniquement lorsque l'écriture d'une nouvelle valeur dans une variable déclarée avec let pourrait nuire au programme. Mais, en apprenant davantage sur la programmation, j'ai changé d'avis à ce sujet. Maintenant, mon outil principal est const , et let moi de ne l'utiliser que lorsque la valeur de la variable doit être réécrite. Cela me fait me demander s'il est vraiment nécessaire de changer la valeur d'une certaine variable. Dans la plupart des cas, cela n'est pas nécessaire.

Avons-nous besoin du mot-clé var?


Les mots clés let et const contribuent à une approche de programmation plus responsable. Y a-t-il des situations où le mot-clé var est toujours nécessaire? Oui, il y en a. Il existe plusieurs situations dans lesquelles ce mot-clé nous est toujours utile. Réfléchissez bien à ce dont nous allons parler avant de changer var en let ou const .

▍ Niveau de prise en charge des mots clés Var par les navigateurs


Les variables déclarées avec le mot-clé var ont une fonctionnalité très importante qui let et const manque. À savoir, nous parlons du fait qu'absolument tous les navigateurs prennent en charge ce mot-clé. Bien que la prise en charge de let et const par les navigateurs soit très bonne, il existe cependant un risque que votre programme se retrouve dans un navigateur qui ne les prend pas en charge. Afin de comprendre les conséquences d'un tel incident, vous devez considérer la façon dont les navigateurs gèrent le code JavaScript non pris en charge, par exemple, comment ils réagissent au code CSS qu'ils ne comprennent pas.

Si le navigateur ne prend pas en charge certaines fonctionnalités CSS, cela entraîne essentiellement une distorsion de ce qui sera affiché à l'écran. Un site dans un navigateur qui ne prend en charge aucun des styles utilisés par le site ne sera pas comme prévu, mais il peut très probablement être utilisé. Si vous utilisez, par exemple, let et que le navigateur ne prend pas en charge ce mot-clé, votre code JS ne fonctionnera tout simplement pas. Ce ne sera pas - c'est tout. Étant donné que JavaScript est l'un des composants importants du Web moderne, cela peut devenir un problème grave si vous avez besoin que vos programmes fonctionnent dans des navigateurs obsolètes.

Lorsque les gens parlent de la prise en charge du navigateur pour les sites, ils demandent généralement dans quel navigateur le site fonctionnera de manière optimale. Si nous parlons d'un site dont la fonctionnalité est basée sur l'utilisation de let et const , alors une question similaire devra être posée différemment: "Dans quels navigateurs notre site ne fonctionnera-t-il pas?". Et cela est beaucoup plus grave que de parler de l'utilisation de l' display: flex ou non. Pour la plupart des sites Web, le nombre d'utilisateurs avec des navigateurs obsolètes ne sera pas assez important pour vous inquiéter. Cependant, si nous parlons de quelque chose comme une boutique en ligne ou des sites dont les propriétaires achètent de la publicité, cela peut être une considération très importante. Avant d'utiliser de nouvelles opportunités dans de tels projets, évaluez le niveau de risque.

Si vous devez prendre en charge des navigateurs très anciens, mais que vous souhaitez utiliser let , const et d'autres nouvelles fonctionnalités ES6, l'une des solutions à ce problème consiste à utiliser un transporteur JavaScript comme Babel . Les transpilers fournissent la traduction du nouveau code dans ce que les anciens navigateurs comprendront. Babel, , , , .

, ? , . , , , , . , . , , . ES6-, Babel, Babel , , . , , . . ? - IE8 ? , , , , , .

▍ var


, var , . . :

 var myVar = 1; function myFunction() { var myVar = 2; //  ,     myVar    ! } 

, myVar , , . , . , , , , . , . var .

 var myVar = 1; function myFunction() { var myVar = 2; console.log(myVar); // 2 console.log(window.myVar); // 1 } 

var , window . let const . , JS- , (, , ) , .

, . , . , , , :

 let myGlobalVars = {}; let myVar = 1; myGlobalVars.myVar = myVar; function myFunction() { let myVar = 2; console.log(myVar); // 2 console.log(myGlobalVars.myVar); // 1 } 

, , , , . , , var , , , , , .

Résumé


, ? ? :

  • IE10 - ? — var .
  • JavaScript, , , var , const . - (, , ) — let .

let const , ECMAScript 6, ( ) - -. , , , . , - , «» «» , , let const , .

! , const var , let , , , ?

Source: https://habr.com/ru/post/fr420359/


All Articles