JavaScript: la portée en termes simples

Bonne journée, mes amis!



La portĂ©e est un concept important pour dĂ©terminer l'accessibilitĂ© des variables. Ce concept est au cƓur des fermetures, divisant les variables en globales et locales.



Dans cet article, je vais essayer d'expliquer en termes simples quelle est la portée de JavaScript.



1. Portée



Avant de plonger dans les détails de la portée, regardons un exemple rapide.



Disons que nous avons défini une variable:



const message = 'Hello'
console.log(message) // 'Hello'


Nous pouvons facilement afficher sa valeur sur la console. C'est clair.



Maintenant, plaçons la déclaration de la variable message dans le bloc if:



if (true) {
    const message = 'Hello'
}
console.log(message) // ReferenceError: message is not defined


Cette fois, lors de la tentative d'accÚs à la variable, une exception ReferenceError: message is not defined est levée.



Pourquoi est-ce arrivé?



Parce que le bloc if a créé une portée pour la variable de message. Et le message n'est disponible que dans cette portée.







Ainsi, la disponibilité des variables est limitée par la portée dans laquelle elles sont définies.



La portée est donc la portée des variables.



2. Bloquer la portée



Un bloc de code en JavaScript définit la portée des variables déclarées avec les mots-clés const et let:



if (true) {
    //    if
    const message = 'Hello'
    console.log(message) // 'Hello'
}
console.log(message) // ReferenceError


Le premier console.log () imprime en toute sécurité la valeur de la variable de message dans la console, puisque cette variable est accessible dans la portée dans laquelle elle est définie.



Cependant, l'appel du second console.log () génÚre une erreur car la variable de message n'est pas disponible dans sa portée externe: le message n'existe pas dans le contexte actuel.



La portée de bloc est également créée dans les instructions if, for, while.



Par exemple:



for (const color of ['green', 'red', 'blue']) {
    //    for
    const message = 'Hi'
    console.log(color) // 'green', 'red', 'blue'
    console.log(message) // 'Hi', 'Hi', 'Hi'
}
console.log(color) // ReferenceError
console.log(message) // ReferenceError


Les variables de couleur et de message n'existent qu'à l'intérieur du bloc for.



La mĂȘme chose est vraie pour l'instruction while:



while (/*  */) {
    //    while
    const message = 'Hi'
    console.log(message) // 'Hi'
}
console.log(message) // ReferenceError


Le message défini dans while n'est disponible que dans cette boucle.



En JavaScript, vous pouvez créer des blocs de code autonomes. Ils définissent également leur propre périmÚtre:



{
    const message = 'Hi'
    console.log(message) // 'Hi'
}
console.log(message) // ReferenceError


2.1. var n'a pas de portée de bloc



Comme nous l'avons vu dans les exemples précédents, un bloc de code crée une portée pour les variables déclarées avec les mots-clés const et let. Cependant, cela ne fonctionne pas pour les variables déclarées avec le mot clé var.



Prenons un exemple:



if (true) {
    //    if
    var count = 0
    console.log(count) // 0
}
console.log(count) // 0


Le nombre de variables est disponible dans le bloc if, comme prévu. Cependant, il est également disponible en dehors de ce bloc!



Le fait est que le bloc de code ne crée pas de portée pour les variables déclarées avec le mot-clé var. Mais la fonction le fait.



3. Portée de la fonction



Les fonctions en JavaScript créent une portée pour toutes les variables, quel que soit le mot clé avec lequel elles sont déclarées (var, const ou let).



Par exemple:



function run() {
    //    run()
    var message = ', , !'
    console.log(message)
}
run() // ', , !'
console.log(message) // ReferenceError


La fonction run () crée une portée. Le message variable est disponible à l'intérieur de la fonction, mais pas à l'extérieur.



De mĂȘme, la fonction crĂ©e une portĂ©e pour les variables dĂ©clarĂ©es avec const et let, et mĂȘme pour d'autres fonctions et expressions de fonction:



function run() {
    //    run()
    const two = 2
    let one = 1
    function run2() {}
    var run3 = () => {}

    console.log(two)
    console.log(one)
    console.log(run2)
    console.log(run3)
}
run() // 2 1 ƒ run2() {} () => {}
console.log(two) // ReferenceError
console.log(one) // ReferenceError
console.log(run2) // ReferenceError
console.log(run3) // ReferenceError


4. Visibilité du module



Les modules ES6 créent également une portée pour les variables, les fonctions et les classes.



Le module cercle crée une constante pi (à usage interne):



//    circle
const pi = 3.14

console.log(pi) // 3.14

//  pi


La variable pi est déclarée dans le module cercle et n'est pas exportée à partir de là.



Ensuite, le module cercle est importé:



import './circle'

console.log(pi) // ReferenceError


La variable pi n'est pas disponible en dehors du module cercle (jusqu'à ce qu'elle soit exportée à l'aide de l'exportation).



La portée modulaire encapsule les modules. Cela signifie que les variables privées (qui ne sont pas exportées) sont utilisées pour les propres besoins du module et sont protégées des accÚs extérieurs.



Ainsi, on peut dire que scope est un mécanisme d'encapsulation de blocs de code, de fonctions et de modules.



5. Les portĂ©es peuvent ĂȘtre imbriquĂ©es



Une caractĂ©ristique intĂ©ressante des Ă©tendues est qu'elles peuvent ĂȘtre imbriquĂ©es les unes dans les autres.



Dans l'exemple suivant, la fonction run () crée une portée, et à l'intérieur, un bloc if crée une autre portée:



function run() {
    //    run()
    const message = ', , !'

    if (true) {
        //    if
        const friend = ''
        console.log(message) // ', , !'
    }

    console.log(friend) // ReferenceError
}
run()


La portée du bloc if est imbriquée dans la portée de la fonction run ().



Une portée qui se trouve à l'intérieur d'une autre portée est appelée une portée interne. Dans l'exemple ci-dessus, il s'agit de la portée du bloc if.



Une étendue qui contient une autre étendue est appelée une étendue externe. Dans l'exemple ci-dessus, c'est la portée de la fonction run ().







Qu'en est-il de la disponibilité variable? Une rÚgle simple à retenir est la suivante: les



variables de la portée externe sont disponibles dans la portée interne.



Par conséquent, la variable de message est disponible dans le bloc if.



6. Portée mondiale



La portée globale est la portée la plus externe. Il est disponible pour toute portée interne ou locale. Dans un navigateur, la portée globale est créée lorsque le fichier JavaScript spécifié dans l'attribut src de la balise script est chargé:



<script src="script.js">




// script.js

// portée globale

let counter = 1



Les variables déclarées dans la portée globale sont des variables globales. Ils sont disponibles dans n'importe quelle autre région.



La portée globale est un mécanisme qui permet au moteur d'exécution JavaScript (navigateur, Node.js) d'exposer des objets hÎtes (c'est-à-dire appartenant à l'environnement) aux applications en tant que variables globales.



Par exemple, la fenĂȘtre et le document sont des variables globales (objets) fournies par le navigateur. Dans Node.js, une telle variable est, par exemple, l'objet de processus.



7. Champ d'application lexical



Définissons deux fonctions, dont l'une est imbriquée dans l'autre:



function outer() {
    //    outer()
    let v = '     outer()!'

    function inner() {
        //    inner()
        console.log(v) // '     outer()!'
    }

    return inner
}

const f = outer()
f()


Jetez un Ɠil Ă  la derniĂšre ligne: inner () est appelĂ© en dehors de la portĂ©e de external (). Comment JavaScript sait-il que la valeur imprimĂ©e sur la console dans la fonction inner () appartient Ă  la variable v dĂ©clarĂ©e dans la fonction external ()?



Réponse: grùce à la portée lexicale.



JavaScript implémente un mécanisme appelé portée lexicale ou statique. La portée lexicale signifie que l'accessibilité des variables est statiquement déterminée par la position de ces variables dans la portée de la fonction imbriquée: les variables de la portée de la fonction externe sont disponibles dans la portée de la fonction imbriquée.



La définition formelle de la portée lexicale est la suivante:



La portée lexicale consiste en des portées externes définies statiquement, c'est-à-dire à partir de régions externes, fixé en utilisant des variables de ces régions dans les fonctions internes.



Dans cet exemple, la portée lexicale de la fonction inner () se compose de la portée de la fonction outside ().



De plus, inner () est une fermeture car il utilise la valeur de la variable de la portée lexicale.



8. Isolement des variables



De toute Ă©vidence, la portĂ©e isole les variables. Cela permet Ă  diffĂ©rentes Ă©tendues de contenir des variables portant le mĂȘme nom.



Vous pouvez utiliser des variables count, index, current, value, etc. dans différentes zones sans risque de collision (conflits de noms).



Par exemple:



function foo() {
    //    foo()
    let count = 1
    console.log(count) // 1
}

function bar() {
    //    bar()
    let count = 2
    console.log(count) // 2
}

foo()
bar()


Conclusion



La portée détermine la disponibilité des variables. Une variable déclarée dans la portée actuelle n'est accessible que dans celle-ci.



En JavaScript, les portées sont créées par des blocs, des fonctions et des modules.



Les variables dĂ©clarĂ©es avec les mots-clĂ©s const et let peuvent ĂȘtre de type bloc, fonctionnel ou modulaire, tandis que les variables dĂ©clarĂ©es avec le mot-clĂ© var n'ont pas de portĂ©e de bloc.



Les portĂ©es peuvent ĂȘtre imbriquĂ©es. Les variables dĂ©clarĂ©es dans la portĂ©e externe sont disponibles dans la portĂ©e interne.



La portĂ©e lexicale consiste en des portĂ©es externes dĂ©finies statiquement. Toute fonction, quel que soit le lieu d'exĂ©cution, a accĂšs aux variables Ă  partir de sa portĂ©e lexicale (c'est l'essence mĂȘme des fermetures).



J'espÚre que l'article vous a été utile. Merci de votre attention.



All Articles