Quelle est la portée des variables en JavaScript?

2013

Quelle est la portée des variables en javascript? Ont-ils la même portée à l'intérieur qu'à l'extérieur d'une fonction? Ou est-ce même important? De plus, où sont stockées les variables si elles sont définies globalement?

lYriCAlsSH
la source
4
Voici un autre lien intéressant pour garder à l'esprit ce problème: " Explication de la portée et des fermetures JavaScript ".
Ingénieur logiciel Full-Stack
9
Voici un article qui l'explique très bien. Tout ce que vous devez savoir sur la portée variable Javascript
Saurab Parakh
2
Le livre électronique de Kyle Simpson mentionné précédemment est disponible à la lecture sur Github, et il vous dit tout ce que vous devez savoir sur les étendues et fermetures JavaScript. Vous pouvez le trouver ici: github.com/getify/You-Dont-Know-JS/blob/master/… Il fait partie de la série de livres "You don't know JS" , ce qui est idéal pour tous ceux qui voudraient savoir en savoir plus sur JavaScript.
3rik82

Réponses:

2536

TLDR

JavaScript a une portée et des fermetures lexicales (également appelées statiques). Cela signifie que vous pouvez déterminer la portée d'un identifiant en consultant le code source.

Les quatre champs d'application sont les suivants:

  1. Global - visible par tout
  2. Fonction - visible dans une fonction (et ses sous-fonctions et blocs)
  3. Bloc - visible dans un bloc (et ses sous-blocs)
  4. Module - visible dans un module

En dehors des cas particuliers de portée globale et de module, les variables sont déclarées à l'aide de var(portée de fonction), let(portée de bloc) et const(portée de bloc). La plupart des autres formes de déclaration d'identifiant ont une portée de bloc en mode strict.

Aperçu

La portée est la région de la base de code sur laquelle un identifiant est valide.

Un environnement lexical est un mappage entre les noms d'identifiants et les valeurs qui leur sont associées.

La portée est formée d'une imbrication liée d'environnements lexicaux, chaque niveau de l'imbrication correspondant à un environnement lexical d'un contexte d'exécution d'ancêtre.

Ces environnements lexicaux liés forment une "chaîne" de portée. La résolution de l'identifiant est le processus de recherche le long de cette chaîne d'un identifiant correspondant.

La résolution de l'identifiant ne se produit que dans une seule direction: vers l'extérieur. De cette façon, les environnements lexicaux externes ne peuvent pas "voir" dans les environnements lexicaux internes.

Il y a trois facteurs pertinents pour décider de la portée d'un identifiant dans JavaScript:

  1. Comment un identifiant a été déclaré
  2. Où un identifiant a été déclaré
  3. Que vous soyez en mode strict ou en mode non strict

Certaines des façons dont les identifiants peuvent être déclarés:

  1. var, letetconst
  2. Paramètres de fonction
  3. Paramètre de bloc de capture
  4. Déclarations de fonctions
  5. Expressions de fonction nommées
  6. Propriétés définies implicitement sur l'objet global (c'est-à-dire manquant varen mode non strict)
  7. import déclarations
  8. eval

Certains des identifiants d'emplacements peuvent être déclarés:

  1. Contexte global
  2. Corps de fonction
  3. Bloc ordinaire
  4. Le sommet d'une structure de contrôle (par exemple, boucle, if, while, etc.)
  5. Corps de la structure de contrôle
  6. Modules

Styles de déclaration

var

Les identificateurs déclarés à l'aide var ont une portée de fonction , sauf lorsqu'ils sont déclarés directement dans le contexte global, auquel cas ils sont ajoutés en tant que propriétés sur l'objet global et ont une portée globale. Il existe des règles distinctes pour leur utilisation dans les evalfonctions.

let et const

Les identifiants déclarés utilisant letet const ont une portée de bloc , sauf lorsqu'ils sont déclarés directement dans le contexte global, auquel cas ils ont une portée globale.

Note: let, constet var sont tous hissés . Cela signifie que leur position logique de définition est au sommet de leur portée englobante (bloc ou fonction). Cependant, les variables ont déclaré utiliser letet constne peuvent pas être lues ou affectées jusqu'à ce que le contrôle ait passé le point de déclaration dans le code source. La période intérimaire est connue comme la zone morte temporelle.

function f() {
    function g() {
        console.log(x)
    }
    let x = 1
    g()
}
f() // 1 because x is hoisted even though declared with `let`!

Noms des paramètres de fonction

Les noms des paramètres de fonction sont étendus au corps de la fonction. Notez qu'il y a une légère complexité à cela. Les fonctions déclarées comme arguments par défaut se ferment sur la liste des paramètres et non sur le corps de la fonction.

Déclarations de fonctions

Les déclarations de fonctions ont une portée de bloc en mode strict et une portée de fonction en mode non strict. Remarque: le mode non strict est un ensemble compliqué de règles émergentes basées sur les implémentations historiques originales de différents navigateurs.

Expressions de fonction nommées

Les expressions de fonction nommées sont limitées à elles-mêmes (par exemple, à des fins de récursivité).

Propriétés définies implicitement sur l'objet global

En mode non strict, les propriétés définies implicitement sur l'objet global ont une portée globale, car l'objet global se trouve en haut de la chaîne de portée. En mode strict, ceux-ci ne sont pas autorisés.

eval

Dans les evalchaînes, les variables déclarées à l'aide varseront placées dans la portée actuelle ou, si elles evalsont utilisées indirectement, comme propriétés sur l'objet global.

Exemples

Ce qui suit lancera une ReferenceError parce que les noms x, yet zn'ont aucune signification en dehors de la fonction f.

function f() {
    var x = 1
    let y = 1
    const z = 1
}
console.log(typeof x) // undefined (because var has function scope!)
console.log(typeof y) // undefined (because the body of the function is a block)
console.log(typeof z) // undefined (because the body of the function is a block)

Ce qui suit lancera une ReferenceError pour yet z, mais pas pour x, car la visibilité de xn'est pas limitée par le bloc. Les blocs qui définissent les corps des structures de contrôle comme if, foret while, se comportent de manière similaire.

{
    var x = 1
    let y = 1
    const z = 1
}
console.log(x) // 1
console.log(typeof y) // undefined because `y` has block scope
console.log(typeof z) // undefined because `z` has block scope

Dans ce qui suit, xest visible en dehors de la boucle car vara une portée de fonction:

for(var x = 0; x < 5; ++x) {}
console.log(x) // 5 (note this is outside the loop!)

... à cause de ce comportement, vous devez faire attention à ne pas fermer les variables déclarées à l'aide varde boucles in. Il n'y a qu'une seule instance de variable xdéclarée ici, et elle se trouve logiquement en dehors de la boucle.

Les impressions suivantes 5, cinq fois, puis 5une sixième fois pour l' console.logextérieur de la boucle:

for(var x = 0; x < 5; ++x) {
    setTimeout(() => console.log(x)) // closes over the `x` which is logically positioned at the top of the enclosing scope, above the loop
}
console.log(x) // note: visible outside the loop

Ce qui suit s'imprime undefinedcar xest de portée bloc. Les rappels sont exécutés un par un de manière asynchrone. Nouveau comportement pour des letmoyens variables que chaque fonction anonyme fermée sur une autre variable nommée x(contrairement à il l' aurait fait avec var), et ainsi entiers à 0travers 4sont imprimés .:

for(let x = 0; x < 5; ++x) {
    setTimeout(() => console.log(x)) // `let` declarations are re-declared on a per-iteration basis, so the closures capture different variables
}
console.log(typeof x) // undefined

Ce qui suit ne lancera PAS un ReferenceErrorcar la visibilité de xn'est pas limitée par le bloc; il s'imprimera cependant undefinedcar la variable n'a pas été initialisée (à cause de l' ifinstruction).

if(false) {
    var x = 1
}
console.log(x) // here, `x` has been declared, but not initialised

Une variable déclarée en haut d'une forboucle à l'aide letest portée au corps de la boucle:

for(let x = 0; x < 10; ++x) {} 
console.log(typeof x) // undefined, because `x` is block-scoped

Ce qui suit lancera un ReferenceErrorcar la visibilité de xest limitée par le bloc:

if(false) {
    let x = 1
}
console.log(typeof x) // undefined, because `x` is block-scoped

Les variables déclarées en utilisant var, letou constsont toutes étendues aux modules:

// module1.js

var x = 0
export function f() {}

//module2.js

import f from 'module1.js'

console.log(x) // throws ReferenceError

Ce qui suit déclarera une propriété sur l'objet global, car les variables déclarées en utilisant vardans le contexte global, sont ajoutées en tant que propriétés à l'objet global:

var x = 1
console.log(window.hasOwnProperty('x')) // true

letet constdans le contexte global n'ajoutent pas de propriétés à l'objet global, mais ont toujours une portée globale:

let x = 1
console.log(window.hasOwnProperty('x')) // false

Les paramètres de fonction peuvent être considérés comme déclarés dans le corps de la fonction:

function f(x) {}
console.log(typeof x) // undefined, because `x` is scoped to the function

Les paramètres du bloc de capture sont limités au corps du bloc de capture:

try {} catch(e) {}
console.log(typeof e) // undefined, because `e` is scoped to the catch block

Les expressions de fonction nommées sont limitées à l'expression elle-même:

(function foo() { console.log(foo) })()
console.log(typeof foo) // undefined, because `foo` is scoped to its own expression

En mode non strict, les propriétés définies implicitement sur l'objet global ont une portée globale. En mode strict, vous obtenez une erreur.

x = 1 // implicitly defined property on the global object (no "var"!)

console.log(x) // 1
console.log(window.hasOwnProperty('x')) // true

En mode non strict, les déclarations de fonction ont une portée de fonction. En mode strict, ils ont une portée de bloc.

'use strict'
{
    function foo() {}
}
console.log(typeof foo) // undefined, because `foo` is block-scoped

Comment ça marche sous le capot

La portée est définie comme la région lexicale du code sur laquelle un identifiant est valide.

En JavaScript, chaque objet-fonction a une [[Environment]]référence cachée qui est une référence à l' environnement lexical du contexte d'exécution (cadre de pile) dans lequel il a été créé.

Lorsque vous appelez une fonction, la [[Call]]méthode cachée est appelée. Cette méthode crée un nouveau contexte d'exécution et établit un lien entre le nouveau contexte d'exécution et l'environnement lexical de l'objet-fonction. Il le fait en copiant la [[Environment]]valeur sur l'objet-fonction, dans un champ de référence externe sur l'environnement lexical du nouveau contexte d'exécution.

Notez que ce lien entre le nouveau contexte d'exécution et l'environnement lexical de l'objet fonction est appelé fermeture .

Ainsi, en JavaScript, la portée est implémentée via des environnements lexicaux reliés entre eux dans une "chaîne" par des références externes. Cette chaîne d'environnements lexicaux est appelée la chaîne de portée, et la résolution de l'identifiant se produit en recherchant dans la chaîne un identifiant correspondant.

Apprenez-en plus .

Triptyque
la source
280
Ce n'est même pas près d'être complet, mais c'est peut-être l'ensemble des astuces de portée Javascript dont vous avez besoin pour même lire efficacement le javascript moderne.
Triptyque du
148
Une réponse très appréciée, je ne sais pas pourquoi. Ce n'est qu'un tas d'exemples sans explication appropriée, puis semble confondre l'héritage du prototype (c'est-à-dire la résolution de propriété) avec la chaîne de portée (c'est-à-dire la résolution variable). Une explication complète (et précise) de la résolution de l'étendue et des propriétés se trouve dans les notes de la FAQ comp.lang.javascript .
RobG
109
@RobG Il est très apprécié car il est utile et compréhensible pour un large éventail de programmeurs, malgré une catachrèse mineure. Le lien que vous avez publié, bien qu'utile pour certains professionnels, est incompréhensible pour la plupart des gens qui écrivent Javascript aujourd'hui. N'hésitez pas à résoudre les problèmes de nomenclature en modifiant la réponse.
Triptyque
7
@ triptyque: je modifie uniquement les réponses pour corriger des problèmes mineurs, pas majeurs. Changer "portée" en "propriété" corrigera l'erreur, mais pas le problème de mélanger l'héritage et la portée sans une distinction très claire.
RobG
24
Si vous définissez une variable dans la portée externe, puis que vous avez une instruction if définissez une variable à l'intérieur de la fonction avec le même nom, même si cette branche n'est pas atteinte, elle est redéfinie. Un exemple - jsfiddle.net/3CxVm
Chris S
233

Javascript utilise des chaînes de portée pour établir la portée d'une fonction donnée. Il existe généralement une étendue globale et chaque fonction définie a sa propre étendue imbriquée. Toute fonction définie dans une autre fonction a une portée locale qui est liée à la fonction externe. C'est toujours la position dans la source qui définit la portée.

Un élément de la chaîne de portée est essentiellement une carte avec un pointeur sur sa portée parent.

Lors de la résolution d'une variable, javascript démarre à l'étendue la plus intérieure et recherche vers l'extérieur.

krosenvold
la source
1
Les chaînes de portée sont un autre terme pour les fermetures [mémoire] ... pour ceux qui lisent ici pour apprendre / entrer en javascript.
New Alexandria
108

Les variables déclarées globalement ont une portée globale. Les variables déclarées dans une fonction sont étendues à cette fonction et masquent les variables globales du même nom.

(Je suis sûr qu'il ya beaucoup de subtilités que les vrais programmeurs JavaScript seront en mesure de signaler dans d' autres réponses. En particulier , je suis tombé sur cette page sur ce que exactement les thismoyens à tout moment. Espérons que ce lien plus d' introduction est assez pour vous aider à démarrer si .)

Jon Skeet
la source
7
J'ai même peur de commencer à répondre à cette question. En tant que vrai programmeur Javascript, je sais à quelle vitesse la réponse pourrait devenir incontrôlable. Bons articles.
Triptyque
10
@Triptych: Je sais ce que vous voulez dire des choses sortir de la main, mais s'il vous plaît ajouter une réponse de toute façon. J'ai obtenu ce qui précède juste en faisant quelques recherches ... une réponse écrite par quelqu'un ayant une expérience réelle est forcément meilleure. Veuillez corriger toute ma réponse qui est définitivement fausse cependant!
Jon Skeet
4
D'une certaine manière, Jon Skeet est responsable de MA réponse la plus populaire sur Stack Overflow.
Triptyque
75

JavaScript old school

Traditionnellement, JavaScript n'a vraiment que deux types de portée:

  1. Portée globale : les variables sont connues tout au long de l'application, dès le début de l'application (*)
  2. Portée fonctionnelle : les variables sont connues dans la fonction dans laquelle elles sont déclarées, depuis le début de la fonction (*)

Je ne m'étendrai pas là-dessus, car il existe déjà de nombreuses autres réponses expliquant la différence.


JavaScript moderne

Les spécifications JavaScript les plus récentes autorisent désormais une troisième portée:

  1. Portée du bloc : les identificateurs sont "connus" du haut de la portée dans laquelle ils sont déclarés , mais ils ne peuvent pas être attribués ou déréférencés (lus) avant la ligne de leur déclaration. Cette période intérimaire est appelée «zone morte temporelle».

Comment créer des variables d'étendue de bloc?

Traditionnellement, vous créez vos variables comme ceci:

var myVariable = "Some text";

Les variables de portée de bloc sont créées comme suit:

let myVariable = "Some text";

Quelle est donc la différence entre la portée fonctionnelle et la portée du bloc?

Pour comprendre la différence entre l'étendue fonctionnelle et l'étendue de bloc, tenez compte du code suivant:

// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here

function loop(arr) {
    // i IS known here, but undefined
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( var i = 0; i < arr.length; i++ ) {
        // i IS known here, and has a value
        // j IS NOT known here
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here

    for( let j = 0; j < arr.length; j++ ) {
        // i IS known here, and has a value
        // j IS known here, and has a value
        // k IS known here, but has a value only the second time loop is called
        // l IS NOT known here
    };

    // i IS known here, and has a value
    // j IS NOT known here
    // k IS known here, but has a value only the second time loop is called
    // l IS NOT known here
}

loop([1,2,3,4]);

for( var k = 0; k < arr.length; k++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS NOT known here
};

for( let l = 0; l < arr.length; l++ ) {
    // i IS NOT known here
    // j IS NOT known here
    // k IS known here, and has a value
    // l IS known here, and has a value
};

loop([1,2,3,4]);

// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here

Ici, nous pouvons voir que notre variable jn'est connue que dans la première boucle for, mais pas avant ni après. Pourtant, notre variable iest connue dans toute la fonction.

Tenez également compte du fait que les variables de portée de bloc ne sont pas connues avant d'être déclarées car elles ne sont pas hissées. Vous n'êtes pas non plus autorisé à redéclarer la même variable de portée de bloc dans le même bloc. Cela rend les variables de portée de bloc moins sujettes aux erreurs que les variables de portée globale ou fonctionnelle, qui sont hissées et qui ne produisent aucune erreur en cas de déclarations multiples.


Est-il sûr d'utiliser des variables d'étendue de bloc aujourd'hui?

Que son utilisation soit sûre ou non aujourd'hui, cela dépend de votre environnement:

  • Si vous écrivez du code JavaScript côté serveur ( Node.js ), vous pouvez utiliser l' letinstruction en toute sécurité .

  • Si vous écrivez du code JavaScript côté client et utilisez un transpilateur basé sur un navigateur (comme Traceur ou babel-standalone ), vous pouvez utiliser en toute sécurité l' letinstruction, cependant votre code est susceptible d'être tout sauf optimal en termes de performances.

  • Si vous écrivez du code JavaScript côté client et utilisez un transpilateur basé sur Node (comme le script shell traceur ou Babel ), vous pouvez utiliser l' letinstruction en toute sécurité . Et comme votre navigateur ne connaîtra que le code transpilé, les inconvénients de performances devraient être limités.

  • Si vous écrivez du code JavaScript côté client et n'utilisez pas de transpilateur, vous devez considérer la prise en charge du navigateur.

    Voici quelques navigateurs qui ne prennent pas en charge letdu tout:

    • Internet Explorer 10 et versions antérieures
    • Firefox 43 et inférieur
    • Safari 9 et inférieur
    • Navigateur Android 4 et inférieur
    • Opera 27 et inférieur
    • Chome 40 et moins
    • TOUTE version d' Opera Mini et Blackberry Browser

entrez la description de l'image ici


Comment suivre la prise en charge du navigateur

Pour une vue d'ensemble à jour des navigateurs qui prennent en charge la letdéclaration au moment de la lecture de cette réponse, consultez cette Can I Usepage .


(*) Les variables de portée globale et fonctionnelle peuvent être initialisées et utilisées avant d'être déclarées car les variables JavaScript sont hissées . Cela signifie que les déclarations sont toujours bien en haut de la portée.

John Slegers
la source
2
"N'EST PAS connu" est trompeur, car la variable y est déclarée en raison d'un hissage.
Oriol
L'exemple ci-dessus est trompeur, les variables «i» et «j» ne sont pas connues en dehors du bloc. Les variables «Let» n'ont de portée que dans ce bloc particulier et non en dehors du bloc. Let a aussi d'autres avantages, vous ne pouvez pas redéclarer la variable à nouveau et elle a la portée lexicale.
zakir
1
Cela a été utile, merci! Je pense qu'il serait encore plus utile de préciser ce que vous entendez par "JavaScript moderne" et "JavaScript old school"; Je pense que ceux-ci correspondent à ECMAScript 6 / ES6 / ECMAScript 2015 et aux versions antérieures, respectivement?
Jon Schneider
1
@ JonSchneider: correct! Lorsque je dis «JavaScript old school», je parle d'ECMAScript 5 et lorsque je fais référence à «Javascript moderne», je parle d'ECMAScript 6 (alias ECMAScript 2015). Je ne pensais pas qu'il était vraiment si important d'entrer dans les détails ici, cependant, comme la plupart des gens veulent juste savoir (1) quelle est la différence entre l'étendue du bloc et l'étendue fonctionnelle, (2) quels navigateurs prennent en charge l'étendue du bloc et (3) s'il est sûr d'utiliser l'étendue des blocs aujourd'hui pour n'importe quel projet sur lequel ils travaillent. J'ai donc concentré ma réponse sur la résolution de ces problèmes.
John Slegers
1
@JonSchneider: (suite) Néanmoins, je viens d'ajouter un lien vers un article de Smashing Magazine sur ES6 / ES2015 pour ceux qui veulent en savoir plus sur les fonctionnalités qui ont été ajoutées à JavaScript au cours des deux dernières années ... de toute autre personne qui pourrait se demander ce que je veux dire par "JavaScript moderne".
John Slegers
39

Voici un exemple:

<script>

var globalVariable = 7; //==window.globalVariable

function aGlobal( param ) { //==window.aGlobal(); 
                            //param is only accessible in this function
  var scopedToFunction = {
    //can't be accessed outside of this function

    nested : 3 //accessible by: scopedToFunction.nested
  };

  anotherGlobal = {
    //global because there's no `var`
  }; 

}

</script>

Vous voudrez enquêter sur les fermetures et savoir comment les utiliser pour créer des membres privés .

geowa4
la source
31

La clé, si je comprends bien, est que Javascript a une portée de niveau de fonction par rapport à la portée de bloc C la plus courante.

Voici un bon article sur le sujet.

James McMahon
la source
26

Dans "Javascript 1.7" (l'extension de Mozilla à Javascript), on peut également déclarer des variables de portée de bloc avec l' letinstruction :

 var a = 4;
 let (a = 3) {
   alert(a); // 3
 }
 alert(a);   // 4
kennytm
la source
2
Oui, mais est-ce sûr à utiliser? Je veux dire, choisirais-je de façon réaliste cette implémentation si mon code s'exécute dans WebKit?
IgorGanapolsky
10
@Python: Non, WebKit ne prend pas en charge let.
kennytm
Je suppose que la seule utilisation valable pour cela serait si vous saviez que tous les clients utiliseraient un navigateur Mozilla comme pour un système interne d'entreprise.
GazB
Ou si vous programmez en utilisant le framework XUL, le framework d'interface de Mozilla où vous construisez en utilisant css, xml et javascript.
Gerard ONeill
1
@GazB même c'est une idée horrible! Donc, aujourd'hui, vous savez que vos clients utilisent Mozilla, un nouveau mémo indique que maintenant ils utilisent autre chose. IE la raison pour laquelle notre système de paie est nul ... Vous devez utiliser IE8 et jamais IE9 ou IE10 ou Firefox ou Chrome car cela ne fonctionnera pas ...
buzzsawddog
25

L'idée de la portée en JavaScript lorsqu'elle a été conçue à l'origine par Brendan Eich est venue du langage de script HyperCard HyperTalk .

Dans cette langue, les affichages étaient similaires à ceux d'une pile de fiches. Il y avait une carte maîtresse appelée arrière-plan. Il était transparent et peut être vu comme la carte du bas. Tout le contenu de cette carte de base a été partagé avec des cartes placées dessus. Chaque carte placée au-dessus avait son propre contenu qui avait priorité sur la carte précédente, mais avait toujours accès aux cartes précédentes si désiré.

C'est exactement comme cela que le système de portée JavaScript est conçu. Il a juste des noms différents. Les cartes en JavaScript sont connues sous le nom de contextes d'exécution ECMA . Chacun de ces contextes contient trois parties principales. Un environnement variable, un environnement lexical et une cette liaison. Pour en revenir à la référence des cartes, l'environnement lexical contient tout le contenu des cartes précédentes plus bas dans la pile. Le contexte actuel est en haut de la pile et tout contenu déclaré y sera stocké dans l'environnement variable. L'environnement variable aura la priorité dans le cas de collisions de noms.

Cette liaison pointera vers l'objet contenant. Parfois, les étendues ou les contextes d'exécution changent sans que l'objet conteneur ne change, comme dans une fonction déclarée où l'objet conteneur peut être windowou une fonction constructeur.

Ces contextes d'exécution sont créés chaque fois que le contrôle est transféré. Le contrôle est transféré lorsque le code commence à s'exécuter, et cela se fait principalement à partir de l'exécution de la fonction.

Voilà donc l'explication technique. En pratique, il est important de se rappeler qu'en JavaScript

  • Les étendues sont techniquement des «contextes d'exécution»
  • Les contextes forment une pile d'environnements où les variables sont stockées
  • Le haut de la pile est prioritaire (le bas étant le contexte global)
  • Chaque fonction crée un contexte d'exécution (mais pas toujours une nouvelle cette liaison)

En appliquant cela à l'un des exemples précédents (5. "Clôture") de cette page, il est possible de suivre la pile des contextes d'exécution. Dans cet exemple, il y a trois contextes dans la pile. Ils sont définis par le contexte externe, le contexte de la fonction immédiatement invoquée appelée par var six et le contexte de la fonction retournée à l'intérieur de la fonction immédiatement invoquée de var six.

i ) Le contexte extérieur. Il a un environnement variable de a = 1
ii ) Le contexte IIFE, il a un environnement lexical de a = 1, mais un environnement variable de a = 6 qui a priorité dans la pile
iii ) Le contexte de fonction retourné, il a un lexical environnement de a = 6 et qui est la valeur référencée dans l'alerte lors de l'appel.

entrez la description de l'image ici

Travis J
la source
17

1) Il existe une étendue globale, une étendue de fonction et les étendues with et catch. Il n'y a pas de portée de niveau «bloc» en général pour les variables - les instructions with et catch ajoutent des noms à leurs blocs.

2) Les portées sont imbriquées par des fonctions jusqu'à la portée globale.

3) Les propriétés sont résolues en passant par la chaîne du prototype. L'instruction with introduit les noms de propriété d'objet dans la portée lexicale définie par le bloc with.

EDIT: ECMAAScript 6 (Harmony) est spécifié pour prendre en charge let, et je sais que chrome autorise un drapeau «harmonie», donc peut-être qu'il le prend en charge ..

Soit un support pour la portée au niveau du bloc, mais vous devez utiliser le mot-clé pour y arriver.

EDIT: Sur la base des remarques de Benjamin sur les déclarations with et catch dans les commentaires, j'ai édité le post et ajouté plus. Tant le avec et les déclarations de capture des variables dans leurs introduisons blocs respectifs, et qui est un champ de bloc. Ces variables sont aliasées aux propriétés des objets qui leur sont passés.

 //chrome (v8)

 var a = { 'test1':'test1val' }
 test1   // error not defined
 with (a) { var test1 = 'replaced' }
 test1   // undefined
 a       // a.test1 = 'replaced'

EDIT: Exemple de clarification:

test1 est limité au bloc with, mais a un alias vers a.test1. 'Var test1' crée une nouvelle variable test1 dans le contexte lexical supérieur (fonction ou global), à moins que ce ne soit une propriété de a - ce qu'elle est.

Oui! Soyez prudent en utilisant 'avec' - tout comme var est un noop si la variable est déjà définie dans la fonction, c'est aussi un noop en ce qui concerne les noms importés de l'objet! Un petit avertissement sur le nom déjà défini rendrait cela beaucoup plus sûr. Personnellement, je ne l'utiliserai jamais avec à cause de cela.

Gerard ONeill
la source
Vous avez quelques erreurs ici, car un JavaScript a des formes de portée de bloc.
Benjamin Gruenbaum
Mes oreilles (yeux) sont ouvertes, Benjamin - Mes déclarations ci-dessus montrent comment j'ai traité la portée de Javascript, mais elles ne sont pas basées sur la lecture des spécifications. Et j'espère que vous ne faites pas référence à l'instruction with (qui est une forme de portée d'objet), ou à la syntaxe spéciale «let» de Mozilla.
Gerard ONeill
Eh bien, l' withinstruction est une forme de portée de bloc, mais les catchclauses sont une forme beaucoup plus courante (Fait amusant, v8 implémente catchavec a with) - c'est à peu près les seules formes de portée de bloc dans JavaScript lui-même (c'est-à-dire, fonction, global, try / catch , avec et leurs dérivés), mais les environnements hôtes ont différentes notions de portée - par exemple les événements en ligne dans le navigateur et le module vm de NodeJS.
Benjamin Gruenbaum
Benjamin - d'après ce que je peux voir, à la fois avec et catch, n'introduisez l'objet que dans la portée actuelle (et donc les propriétés), mais après la fin du bloc respectif, les variables sont réinitialisées. Mais par exemple, une nouvelle variable introduite dans un catch aura la portée de la fonction / méthode englobante.
Gerard ONeill du
2
C'est exactement ce que signifie l'étendue des blocs :)
Benjamin Gruenbaum
9

J'ai constaté que de nombreuses personnes nouvelles dans JavaScript ont du mal à comprendre que l'héritage est disponible par défaut dans le langage et que la portée de la fonction est la seule portée jusqu'à présent. J'ai fourni une extension à un embellisseur que j'ai écrit à la fin de l'année dernière, appelé JSPretty. Les couleurs de fonction ont une portée dans le code et associent toujours une couleur à toutes les variables déclarées dans cette portée. La fermeture est démontrée visuellement lorsqu'une variable avec une couleur d'une étendue est utilisée dans une étendue différente.

Essayez la fonctionnalité sur:

Voir une démo sur:

Consultez le code sur:

Actuellement, la fonctionnalité prend en charge une profondeur de 16 fonctions imbriquées, mais ne colore actuellement pas les variables globales.

austincheney
la source
1
Ne fonctionne pas pour moi avec Firefox 26. Je colle du code ou charge un fichier, cliquez sur Exécuter et rien ne se passe.
mplwork
La portée et l'héritage sont deux choses différentes.
Ben Aston
9

JavaScript n'a que deux types de portée:

  1. Portée globale : Global n'est rien d'autre qu'une portée au niveau de la fenêtre. Ici, variable présente dans toute l'application.
  2. Portée fonctionnelle : la variable déclarée dans une fonction avec un varmot clé a une portée fonctionnelle.

Chaque fois qu'une fonction est appelée, un objet de portée variable est créé (et inclus dans la chaîne de portée) qui est suivi par des variables en JavaScript.

        a = "global";
         function outer(){ 
              b = "local";
              console.log(a+b); //"globallocal"
         }
outer();

Chaîne de lunette ->

  1. Niveau de fenêtre - aet la outerfonction sont au niveau supérieur dans la chaîne de portée.
  2. lorsque la fonction externe a appelé une nouvelle variable scope object(et incluse dans la chaîne de portée) ajoutée avec une variable à l' bintérieur.

Maintenant, lorsqu'une variable est arequise, elle recherche d'abord l'étendue de la variable la plus proche et si la variable n'est pas là, elle se déplace vers l'objet suivant de la chaîne d'étendue de la variable.

Anshul
la source
1
Je ne sais pas pourquoi ce n'est pas la réponse acceptée. Il n'y a en fait qu'une portée fonctionnelle (avant ECMA6 il n'y avait pas de "portée locale") et des liaisons globales
texasbruce
9

Juste pour ajouter aux autres réponses, la portée est une liste de recherche de tous les identificateurs déclarés (variables), et applique un ensemble strict de règles quant à la façon dont celles-ci sont accessibles au code en cours d'exécution. Cette recherche peut être effectuée dans le but d'affecter à la variable, qui est une référence LHS (côté gauche), ou dans le but de récupérer sa valeur, qui est une référence RHS (côté droit). Ces recherches sont ce que fait le moteur JavaScript en interne lorsqu'il compile et exécute le code.

Donc, de ce point de vue, je pense qu'une image serait utile que j'ai trouvée dans l'ebook Scopes and Closures de Kyle Simpson:

image

Citant de son ebook:

Le bâtiment représente l'ensemble de règles de portée imbriquée de notre programme. Le premier étage du bâtiment représente votre périmètre en cours d'exécution, où que vous soyez. Le niveau supérieur du bâtiment est la portée mondiale. Vous résolvez les références LHS et RHS en regardant à votre étage actuel, et si vous ne le trouvez pas, en prenant l'ascenseur à l'étage suivant, en y regardant, puis au suivant, etc. Une fois arrivé au dernier étage (la portée mondiale), soit vous trouvez ce que vous cherchez, soit vous ne le trouvez pas. Mais vous devez vous arrêter malgré tout.

Une chose à noter, "La recherche de portée s'arrête une fois qu'elle trouve la première correspondance".

Cette idée de «niveaux de portée» explique pourquoi «ceci» peut être modifié avec une portée nouvellement créée, si elle est recherchée dans une fonction imbriquée. Voici un lien qui rentre dans tous ces détails, Tout ce que vous vouliez savoir sur la portée javascript

James Drinkard
la source
8

exécutez le code. espérons que cela vous donnera une idée de la portée

Name = 'global data';
document.Name = 'current document data';
(function(window,document){
var Name = 'local data';
var myObj = {
    Name: 'object data',
    f: function(){
        alert(this.Name);
    }
};

myObj.newFun = function(){
    alert(this.Name);
}

function testFun(){
    alert("Window Scope : " + window.Name + 
          "\nLocal Scope : " + Name + 
          "\nObject Scope : " + this.Name + 
          "\nCurrent document Scope : " + document.Name
         );
}


testFun.call(myObj);
})(window,document);
Yeasin Abedin Siam
la source
8

Portée mondiale:

Les variables globales sont exactement comme les étoiles globales (Jackie Chan, Nelson Mandela). Vous pouvez y accéder (obtenir ou définir la valeur), à partir de n'importe quelle partie de votre application. Les fonctions globales sont comme des événements mondiaux (Nouvel An, Noël). Vous pouvez les exécuter (appeler) à partir de n'importe quelle partie de votre application.

//global variable
var a = 2;

//global function
function b(){
   console.log(a);  //access global variable
}

Portée locale:

Si vous êtes aux États-Unis, vous connaissez peut-être Kim Kardashian, une célébrité infâme (elle parvient en quelque sorte à faire les tabloïds). Mais les gens en dehors des États-Unis ne la reconnaîtront pas. C'est une star locale, liée à son territoire.

Les variables locales sont comme des étoiles locales. Vous ne pouvez y accéder (obtenir ou définir la valeur) qu'à l'intérieur de la portée. Une fonction locale est comme des événements locaux - vous ne pouvez exécuter (célébrer) que dans cette portée. Si vous souhaitez y accéder depuis l'extérieur de la portée, vous obtiendrez une erreur de référence

function b(){
   var d = 21; //local variable
   console.log(d);

   function dog(){  console.log(a); }
     dog(); //execute local function
}

 console.log(d); //ReferenceError: dddddd is not defined    

Consultez cet article pour une compréhension approfondie de la portée

Jhankar Mahbub
la source
6

Il existe PRESQUE seulement deux types d'étendues JavaScript:

  • la portée de chaque déclaration var est associée à la fonction englobante la plus immédiate
  • s'il n'y a pas de fonction englobante pour une déclaration var, c'est la portée globale

Ainsi, tous les blocs autres que les fonctions ne créent pas de nouvelle étendue. Cela explique pourquoi les boucles for remplacent les variables de portée externes:

var i = 10, v = 10;
for (var i = 0; i < 5; i++) { var v = 5; }
console.log(i, v);
// output 5 5

Utiliser des fonctions à la place:

var i = 10, v = 10;
$.each([0, 1, 2, 3, 4], function(i) { var v = 5; });
console.log(i,v);
// output 10 10

Dans le premier exemple, il n'y avait pas de portée de bloc, donc les variables initialement déclarées ont été écrasées. Dans le deuxième exemple, il y avait une nouvelle portée en raison de la fonction, donc les variables initialement déclarées étaient SHADOWED, et non écrasées.

C'est presque tout ce que vous devez savoir en termes de portée de JavaScript, sauf:

Vous pouvez donc voir que la portée de JavaScript est en fait extrêmement simple, mais pas toujours intuitive. Quelques choses à savoir:

  • Les déclarations var sont hissées en haut de l'étendue. Cela signifie que peu importe où la déclaration var se produit, pour le compilateur, c'est comme si la var elle-même se produisait en haut
  • plusieurs déclarations var dans la même étendue sont combinées

Donc, ce code:

var i = 1;
function abc() {
  i = 2;
  var i = 3;
}
console.log(i);     // outputs 1

est équivalent à:

var i = 1;
function abc() {
  var i;     // var declaration moved to the top of the scope
  i = 2;
  i = 3;     // the assignment stays where it is
}
console.log(i);

Cela peut sembler contre-intuitif, mais il est logique du point de vue d'un concepteur de langage impératif.

jackbean818
la source
5

Js modernes, ES6 +, ' const' et 'let '

Vous devez utiliser l'étendue des blocs pour chaque variable que vous créez, comme la plupart des autres langages principaux. varest obsolète . Cela rend votre code plus sûr et plus facile à gérer.

constdoit être utilisé dans 95% des cas . Il fait en sorte que la référence de variable ne puisse pas changer. Les propriétés des tableaux, des objets et des nœuds DOM peuvent changer et devraient probablement êtreconst .

letdoit être utilisé pour toute variable devant être réaffectée. Cela inclut une boucle for. Si vous changez la valeur au-delà de l'initialisation, utilisezlet .

La portée du bloc signifie que la variable ne sera disponible que dans les crochets dans lesquels elle est déclarée. Cela s'étend aux étendues internes, y compris les fonctions anonymes créées dans votre étendue.

Gibolt
la source
3

Essayez cet exemple curieux. Dans l'exemple ci-dessous, si a était un numérique initialisé à 0, vous verriez 0 puis 1. Sauf que a est un objet et que javascript passera f1 un pointeur de a plutôt qu'une copie de celui-ci. Le résultat est que vous obtenez la même alerte les deux fois.

var a = new Date();
function f1(b)
{
    b.setDate(b.getDate()+1);
    alert(b.getDate());
}
f1(a);
alert(a.getDate());
Mig82
la source
3

Il n'y a que des étendues de fonction dans JS. Ne bloquez pas les portées! Vous pouvez également voir ce qui est hissé.

var global_variable = "global_variable";
var hoisting_variable = "global_hoist";

// Global variables printed
console.log("global_scope: - global_variable: " + global_variable);
console.log("global_scope: - hoisting_variable: " + hoisting_variable);

if (true) {
    // The variable block will be global, on true condition.
    var block = "block";
}
console.log("global_scope: - block: " + block);

function local_function() {
    var local_variable = "local_variable";
    console.log("local_scope: - local_variable: " + local_variable);
    console.log("local_scope: - global_variable: " + global_variable);
    console.log("local_scope: - block: " + block);
    // The hoisting_variable is undefined at the moment.
    console.log("local_scope: - hoisting_variable: " + hoisting_variable);

    var hoisting_variable = "local_hoist";
    // The hoisting_variable is now set as a local one.
    console.log("local_scope: - hoisting_variable: " + hoisting_variable);
}

local_function();

// No variable in a separate function is visible into the global scope.
console.log("global_scope: - local_variable: " + local_variable);
koredalin
la source
(longtemps depuis la réponse publiée) Portée du bloc; developer.mozilla.org/en/docs/Web/JavaScript/Reference/…
Bob
2

Je crois comprendre qu'il y a 3 portées: portée mondiale, disponible à l'échelle mondiale; portée locale, disponible pour une fonction entière indépendamment des blocs; et la portée du bloc, uniquement disponible pour le bloc, l'instruction ou l'expression sur laquelle il a été utilisé. La portée globale et locale est indiquée par le mot-clé «var», à l'intérieur ou à l'extérieur d'une fonction, et la portée du bloc est indiquée par le mot-clé «let».

Pour ceux qui pensent qu'il n'y a qu'une portée globale et locale, veuillez expliquer pourquoi Mozilla aurait une page entière décrivant les nuances de la portée des blocs dans JS.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let

mrmaclean89
la source
2

Un problème très courant qui n'est pas encore décrit et que les codeurs frontaux rencontrent souvent est l'étendue visible par un gestionnaire d'événements en ligne dans le HTML - par exemple, avec

<button onclick="foo()"></button>

La portée des variables qu'un on*attribut peut référencer doit être soit:

  • global (les gestionnaires en ligne de travail font presque toujours référence aux variables globales)
  • une propriété du document (par exemple, querySelectorcomme une variable autonome pointera vers document.querySelector; rare)
  • une propriété de l'élément auquel le gestionnaire est attaché (comme ci-dessus; rare)

Sinon, vous obtiendrez une ReferenceError lorsque le gestionnaire est appelé. Ainsi, par exemple, si le gestionnaire en ligne fait référence à une fonction définie à l' intérieur de window.onload ou $(function() {, la référence échouera, car le gestionnaire en ligne peut uniquement référencer des variables dans la portée globale et la fonction n'est pas globale:

Les propriétés de documentet les propriétés de l'élément auquel le gestionnaire est attaché peuvent également être référencées en tant que variables autonomes dans les gestionnaires en ligne car les gestionnaires en ligne sont appelés à l' intérieur de deux withblocs , un pour le document, un pour l'élément. La chaîne de portée des variables à l'intérieur de ces gestionnaires est extrêmement peu intuitive , et un gestionnaire d'événements de travail nécessitera probablement une fonction pour être globale (et une pollution globale inutile devrait probablement être évitée ).

Étant donné que la chaîne de portée à l'intérieur des gestionnaires en ligne est si étrange et que les gestionnaires en ligne nécessitent une pollution globale pour fonctionner et que les gestionnaires en ligne nécessitent parfois un échappement de chaîne laid lors du passage d'arguments, il est probablement plus facile de les éviter. Au lieu de cela, attachez des gestionnaires d'événements à l'aide de Javascript (comme avec addEventListener), plutôt qu'avec du balisage HTML.


Sur une note différente, contrairement aux <script>balises normales , qui s'exécutent au niveau supérieur, le code à l'intérieur des modules ES6 s'exécute dans sa propre portée privée. Une variable définie en haut d'une <script>balise normale est globale, vous pouvez donc la référencer dans d'autres <script>balises, comme ceci:

Mais le niveau supérieur d'un module ES6 n'est pas global. Une variable déclarée en haut d'un module ES6 ne sera visible qu'à l'intérieur de ce module, à moins que la variable ne soit explicitement exportéditée, ou à moins qu'elle ne soit affectée à une propriété de l'objet global.

Le niveau supérieur d'un module ES6 est similaire à celui de l'intérieur d'un IIFE au niveau supérieur dans une normale <script>. Le module peut référencer toutes les variables qui sont globales, et rien ne peut référencer quoi que ce soit à l'intérieur du module à moins que le module ne soit explicitement conçu pour cela.

CertainPerformance
la source
1

En JavaScript, il existe deux types de portée:

  • Portée locale
  • Portée mondiale

La fonction ci-dessous a une variable de portée locale carName. Et cette variable n'est pas accessible de l'extérieur de la fonction.

function myFunction() {
    var carName = "Volvo";
    alert(carName);
    // code here can use carName
}

La classe ci-dessous a une variable de portée globale carName. Et cette variable est accessible de partout dans la classe.

class {

    var carName = " Volvo";

    // code here can use carName

    function myFunction() {
        alert(carName);
        // code here can use carName 
    }
}
Abdur Rahman
la source
1

ES5 et plus tôt:

Les variables en Javascript avaient initialement une ES6portée (pré ) lexicale. Le terme à portée lexicale signifie que vous pouvez voir la portée des variables en «regardant» le code.

Chaque variable déclarée avec le varmot clé est étendue à la fonction. Cependant, si d'autres fonctions sont déclarées dans cette fonction, ces fonctions auront accès aux variables des fonctions externes. C'est ce qu'on appelle une chaîne de portée . Cela fonctionne de la manière suivante:

  1. Lorsqu'une fonction cherche à résoudre une valeur de variable, elle examine d'abord sa propre portée. Ceci est le corps de la fonction, c'est-à-dire tout ce qui se trouve entre crochets {} (sauf pour les variables à l'intérieur autres fonctions qui sont dans cette portée).
  2. S'il ne trouve pas la variable à l'intérieur du corps de la fonction, il montera jusqu'à la chaîne et examinera la portée de la variable dans la fonction dans laquelle la fonction a été définie . C'est ce que l'on entend par portée lexicale, nous pouvons voir dans le code où cette fonction a été définie et ainsi déterminer la chaîne de portée en regardant simplement le code.

Exemple:

// global scope
var foo = 'global';
var bar = 'global';
var foobar = 'global';

function outerFunc () {
 // outerFunc scope
 var foo = 'outerFunc';
 var foobar = 'outerFunc';
 innerFunc();
 
 function innerFunc(){
 // innerFunc scope
  var foo = 'innerFunc';
  console.log(foo);
  console.log(bar);
  console.log(foobar);
  }
}

outerFunc();

Que se passe-t-il lorsque nous essayons de consigner les variables foo,bar et foobarla console est la suivante:

  1. Nous essayons de connecter foo à la console, foo peut être trouvé dans la fonction innerFunc elle-même. Par conséquent, la valeur de foo est résolue dans la chaîne innerFunc.
  2. Nous essayons de connecter la barre à la console, la barre est introuvable dans la fonction innerFuncelle-même. Par conséquent, nous devons gravir la chaîne de portée . Nous examinons d'abord la fonction extérieure dans laquelle la fonctioninnerFunc été définie. Telle est la fonction outerFunc. Dans le cadre de, outerFuncnous pouvons trouver la barre de variables, qui contient la chaîne 'externalFunc'.
  3. foobar est introuvable dans innerFunc. . Par conséquent, nous devons escalader la chaîne de portée jusqu'à la portée innerFunc. Il ne peut pas non plus être trouvé ici, nous montons un autre niveau à la portée mondiale (c'est-à-dire la portée la plus externe). Nous trouvons ici la variable foobar qui contient la chaîne «global». S'il n'avait pas trouvé la variable après avoir grimpé la chaîne de portée, le moteur JS lancerait une référenceError .

ES6 (ES 2015) et plus ancien:

Les mêmes concepts de portée lexicale et de chaîne de portée s'appliquent toujours ES6. Cependant, de nouvelles façons de déclarer les variables ont été introduites. Il y a ce qui suit:

  • let: crée une variable de portée de bloc
  • const: crée une variable de portée de bloc qui doit être initialisée et ne peut pas être réaffectée

La plus grande différence entre varet let/ constest la varportée de la fonction tandis que let/ constest la portée du bloc. Voici un exemple pour illustrer cela:

let letVar = 'global';
var varVar = 'global';

function foo () {
  
  if (true) {
    // this variable declared with let is scoped to the if block, block scoped
    let letVar = 5;
    // this variable declared with let is scoped to the function block, function scoped
    var varVar = 10;
  }
  
  console.log(letVar);
  console.log(varVar);
}


foo();

Dans l'exemple ci-dessus, letVar enregistre la valeur globale car les variables déclarées avec letsont de portée bloc. Ils cessent d'exister en dehors de leur bloc respectif, de sorte que la variable n'est pas accessible en dehors du bloc if.

Willem van der Veen
la source
0

Dans EcmaScript5, il existe principalement deux étendues, portée locale et portée globale, mais dans EcmaScript6, nous avons principalement trois étendues, portée locale, portée globale et une nouvelle portée appelée étendue de bloc .

Exemple de portée de bloc: -

for ( let i = 0; i < 10; i++)
{
 statement1...
statement2...// inside this scope we can access the value of i, if we want to access the value of i outside for loop it will give undefined.
}
Vivek Mehta
la source
0

ECMAScript 6 a introduit les mots clés let et const. Ces mots clés peuvent être utilisés à la place du mot clé var. Contrairement au mot clé var, les mots clés let et const prennent en charge la déclaration de portée locale à l'intérieur des instructions de bloc.

var x = 10
let y = 10
const z = 10
{
  x = 20
  let y = 20
  const z = 20
  {
    x = 30
    // x is in the global scope because of the 'var' keyword
    let y = 30
    // y is in the local scope because of the 'let' keyword
    const z = 30
    // z is in the local scope because of the 'const' keyword
    console.log(x) // 30
    console.log(y) // 30
    console.log(z) // 30
  }
  console.log(x) // 30
  console.log(y) // 20
  console.log(z) // 20
}

console.log(x) // 30
console.log(y) // 10
console.log(z) // 10
Davaakhuu Erdenekhuu
la source
0

J'aime vraiment la réponse acceptée mais je veux ajouter ceci:

Scope collecte et gère une liste de recherche de tous les identifiants déclarés (variables) et applique un ensemble strict de règles sur la façon dont celles-ci sont accessibles au code en cours d'exécution.

La portée est un ensemble de règles pour rechercher des variables par leur nom d'identifiant.

  • Si une variable est introuvable dans la portée immédiate, le moteur consulte la prochaine portée extérieure contenante, en continuant jusqu'à ce qu'elle soit trouvée ou jusqu'à ce que la portée la plus externe (aka, globale) soit atteinte.
  • Ensemble de règles qui détermine où et comment une variable (identifiant) peut être recherchée. Cette recherche peut être effectuée dans le but d'affecter à la variable, qui est une référence LHS (côté gauche), ou dans le but de récupérer sa valeur, qui est une référence RHS (côté droit). .
  • Les références LHS résultent des opérations d'affectation. Les affectations liées à l'étendue peuvent se produire soit avec l'opérateur =, soit en passant des arguments aux paramètres de fonction (assign to).
  • Le moteur JavaScript compile d'abord le code avant de s'exécuter et, ce faisant, il divise les instructions comme var a = 2; en deux étapes distinctes: 1ère. Tout d'abord, var a pour le déclarer dans cette étendue. Ceci est effectué au début, avant l'exécution du code. 2e. Plus tard, a = 2 pour rechercher la variable (référence LHS) et l'affecter si elle est trouvée.
  • Les recherches de référence LHS et RHS commencent à la portée en cours d'exécution, et si besoin est (c'est-à-dire qu'elles ne trouvent pas ce qu'elles recherchent là-bas), elles remontent la portée imbriquée, une portée (étage ) à la fois, à la recherche de l'identifiant, jusqu'à ce qu'ils atteignent le niveau global (dernier étage) et s'arrêtent, et qu'ils le trouvent ou non. Les références RHS non remplies entraînent le renvoi de ReferenceError. Les références LHS non remplies se traduisent par un global automatique, implicitement créé de ce nom (s'il n'est pas en mode strict), ou une ReferenceError (s'il est en mode strict).
  • scope consiste en une série de «bulles» qui agissent chacune comme un conteneur ou un bucket, dans lequel des identifiants (variables, fonctions) sont déclarés. Ces bulles s'emboîtent parfaitement les unes dans les autres, et cette imbrication est définie au moment de l'auteur.
Ahmed KhaShaba
la source
-3

Il existe deux types de portées en JavaScript.

  1. Portée globale : la variable annoncée dans la portée globale peut être utilisée n'importe où dans le programme très facilement. Par exemple:

    var carName = " BMW";
    
    // code here can use carName
    
    function myFunction() {
         // code here can use carName 
    }
  2. Portée fonctionnelle ou Portée locale : la variable déclarée dans cette portée ne peut être utilisée que dans sa propre fonction. Par exemple:

    // code here can not use carName
    function myFunction() {
       var carName = "BMW";
       // code here can use carName
    }
A. Randhawa
la source