web-dev-qa-db-fra.com

Quelle est la portée des variables en JavaScript?

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? En outre, où sont stockées les variables si elles sont définies globalement?

1918
lYriCAlsSH

Je pense que le mieux que je puisse faire est de vous donner une foule d’exemples à étudier. Les programmeurs Javascript sont pratiquement classés en fonction de leur compréhension de la portée. Cela peut parfois être assez contre-intuitif.

  1. Une variable globale

    // global scope
    var a = 1;
    
    function one() {
      alert(a); // alerts '1'
    }
    
  2. Portée locale

    // global scope
    var a = 1;
    
    function two(a) { // passing (a) makes it local scope
      alert(a); // alerts the given argument, not the global value of '1'
    }
    
    // local scope again
    function three() {
      var a = 3;
      alert(a); // alerts '3'
    }
    
  3. Intermédiaire : La portée de bloc en JavaScript n'existe pas (ES5; ES6 introduit let )

    une.

    var a = 1;
    
    function four() {
      if (true) {
        var a = 4;
      }
    
      alert(a); // alerts '4', not the global value of '1'
    }
    

    b.

    var a = 1;
    
    function one() {
      if (true) {
        let a = 4;
      }
    
      alert(a); // alerts '1' because the 'let' keyword uses block scoping
    }
    
  4. Intermédiaire : Propriétés de l'objet

    var a = 1;
    
    function Five() {
      this.a = 5;
    }
    
    alert(new Five().a); // alerts '5'
    
  5. Avancé : Fermeture

    var a = 1;
    
    var six = (function() {
      var a = 6;
    
      return function() {
        // JavaScript "closure" means I have access to 'a' in here,
        // because it is defined in the function in which I was defined.
        alert(a); // alerts '6'
      };
    })();
    
  6. Avancé : Résolution de la portée basée sur un prototype

    var a = 1;
    
    function seven() {
      this.a = 7;
    }
    
    // [object].prototype.property loses to
    // [object].property in the lookup chain. For example...
    
    // Won't get reached, because 'a' is set in the constructor above.
    seven.prototype.a = -1;
    
    // Will get reached, even though 'b' is NOT set in the constructor.
    seven.prototype.b = 8;
    
    alert(new seven().a); // alerts '7'
    alert(new seven().b); // alerts '8'
    

  7. Global + Local : Un cas très complexe

    var x = 5;
    
    (function () {
        console.log(x);
        var x = 10;
        console.log(x); 
    })();
    

    Ceci affichera undefined et 10 plutôt que 5 et 10, car JavaScript déplace toujours les déclarations de variable (et non les initialisations) en haut de la portée, rendant le code équivalent à:

    var x = 5;
    
    (function () {
        var x;
        console.log(x);
        x = 10;
        console.log(x); 
    })();
    
  8. Variable soumise à une clause de Catch

    var e = 5;
    console.log(e);
    try {
        throw 6;
    } catch (e) {
        console.log(e);
    }
    console.log(e);
    

    Ceci imprimera 5, 6, 5. Dans la clause catch e, masque les variables globales et locales. Mais cette portée spéciale ne concerne que la variable interceptée. Si vous écrivez var f; à l'intérieur de la clause catch, c'est exactement la même chose que si vous l'aviez définie avant ou après le bloc try-catch.

2447
Triptych

Javascript utilise des chaînes d’étendue pour établir l’étendue d’une fonction donnée. Il existe généralement une portée globale et chaque fonction définie a sa propre portée 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 d'étendue est essentiellement une carte avec un pointeur sur l'étendue parente.

Lors de la résolution d'une variable, javascript commence à la portée la plus interne et effectue une recherche vers l'extérieur.

232
krosenvold

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

(Je suis sûr que les vrais programmeurs JavaScript pourront mentionner de nombreuses subtilités dans d'autres réponses. En particulier, je suis tombé sur cette page à propos de ce que signifie exactement this à tout moment. Espérons que ce lien plus introductif est suffisant pour vous aider à démarrer cependant.)

107
Jon Skeet

JavaScript vieille école

Traditionnellement, JavaScript n'a en réalité que deux types de portées:

  1. Portée globale : les variables sont connues dans toute l'application, à partir du début de l'application (*)
  2. Portée fonctionnelle : les variables sont connues dans la fonction ils sont déclarés dans, à partir du début de la fonction (*)

Je n’expliquerai pas cela, car il existe déjà de nombreuses autres réponses expliquant la différence.


JavaScript moderne

Les dernières spécifications JavaScript permettent également un troisième champ d'application:

  1. Portée du bloc : les variables sont connues dans le bloc ils sont déclarés dans, à partir du moment où ils sont déclarés (**)

Comment créer des variables de portée 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";

Alors, quelle est la différence entre la portée fonctionnelle et la portée du bloc?

Pour comprendre la différence entre la portée fonctionnelle et la portée du bloc, considérons le 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 j n’est connue que dans la première boucle for, mais pas avant et après. Cependant, notre variable i est connue dans toute la fonction.

En outre, considérez que les variables de périmètre de bloc ne sont pas connues avant leur déclaration, car elles ne sont pas levées. Vous n'êtes également pas autorisé à redéclarer la même variable de périmètre de bloc dans le même bloc. Cela rend les variables à portée de bloc moins sujettes aux erreurs que les variables à portée globale ou fonctionnelle, qui sont levées et qui ne produisent aucune erreur en cas de déclarations multiples.


Est-il prudent d'utiliser des variables de portée de bloc aujourd'hui?

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

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

  • Si vous écrivez du code JavaScript côté client et utilisez un transpiler basé sur un navigateur (comme ) Traceur ou babel-standalone ), vous pouvez utiliser en toute sécurité l'instruction let, mais votre code est susceptible d'être tout sauf optimal en ce qui concerne la performance.

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

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

    Voici quelques navigateurs qui ne prennent pas en charge let:

    • Internet Explorer 10 et inférieur
    • Firefox 43 et inférieur
    • Safari 9 et inférieur
    • Navigateur Android 4 et inférieur
    • Opera 27 et inférieur
    • Chome 40 et inférieur
    • N'IMPORTE QUELLE version de Opera Mini & Navigateur Blackberry

enter image description here


Comment suivre le support du navigateur

Pour un aperçu à jour des navigateurs qui gèrent l'instruction let au moment de lire cette réponse, voir this Can I Use page .


(*) Les variables globales et fonctionnelles peuvent être initialisées et utilisées avant d'être déclarées car les variables JavaScript sont levées . Cela signifie que les déclarations sont toujours beaucoup au dessus de la portée.

(**) Les variables de périmètre de bloc ne sont pas levées

74
John Slegers

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 étudier les fermetures, et comment les utiliser pour faire private members .

38
geowa4

Si j'ai bien compris, la clé est que Javascript a une portée au niveau de la fonction par rapport à la portée plus courante du bloc C.

Voici un bon article sur le sujet.

31
James McMahon

Dans "Javascript 1.7" (extension de Mozilla à Javascript), on peut également déclarer des variables de bloc avec la commande instruction let :

 var a = 4;
 let (a = 3) {
   alert(a); // 3
 }
 alert(a);   // 4
26
kennytm

L'idée de cadrer en JavaScript lors de la conception initiale de Brendan Eich est venue du HyperCard langage de script HyperTalk .

Dans cette langue, les affichages étaient similaires à une pile de fiches. Il y avait une carte maîtresse appelée arrière-plan. C'était transparent et peut être vu comme la carte du bas. Tout le contenu de cette carte de base était partagé avec des cartes placées dessus. Chaque carte placée au-dessus avait son propre contenu qui prévalait 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 cadrage JavaScript est conçu. Il a juste des noms différents. Les cartes en JavaScript sont appelées Contextes d'exécutionECMA. Chacun de ces contextes contient trois parties principales. Un environnement variable, un environnement lexical et une telle liaison. En revenant à 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 se trouve en haut de la pile et tout contenu déclaré y sera stocké dans l'environnement de variable. La variable environnement aura la priorité en cas de collision de noms.

La liaison this pointera sur l'objet contenant. Parfois, les portées ou les contextes d'exécution changent sans que l'objet contenant ne change, comme dans une fonction déclarée où l'objet contenant peut être window ou une fonction constructeur.

Ces contextes d'exécution sont créés chaque fois que le contrôle temporel est transféré. Le contrôle est transféré lorsque le code commence à s'exécuter, 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 portées sont techniquement des "contextes d'exécution"
  • Les contextes forment une pile d'environnements dans lesquels des 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 liaison)

En appliquant cela à l'un des exemples précédents (5. "Fermeture") de cette page, il est possible de suivre la pile de 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 dans la fonction immédiatement appelée appelée par var six et le contexte dans la fonction renvoyée à l'intérieur de la fonction immédiatement invoquée par var six.

i ) Le contexte externe. 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 prévaut dans la pile.
iii ) Le contexte de la fonction renvoyé a un environnement lexical de = 6 et correspond à la valeur référencée dans l'alerte lors de l'appel.

enter image description here

23
Travis J

1) Il existe une étendue globale, une étendue de fonction et les étendues avec et. 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 étendues sont imbriquées par les fonctions jusqu’à la portée globale.

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

EDIT: ECMAAScript 6 (Harmony) est spécifié pour supporter, et je sais que chrome autorise un drapeau 'harmonie', alors peut-être qu'il le supporte ..

Let serait un support pour la portée au niveau du bloc, mais vous devez utiliser le mot clé pour que cela se produise.

EDIT: Sur la base des remarques de Benjamin sur les déclarations with et catch dans les commentaires, j'ai modifié le message et ajouté d'autres éléments. Les instructions with et catch introduisent toutes les deux des variables dans leurs blocs respectifs, et est une portée de bloc. Ces variables sont associées aux propriétés des objets qui leur ont été transmis.

 //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 est associé à a.test1. 'Var test1' crée une nouvelle variable test1 dans le contexte lexical supérieur (fonction ou global), à moins qu'il ne s'agisse d'une propriété de a - ce qui est le cas.

Beurk! Soyez prudent en utilisant 'avec' - tout comme var est un noop si la variable est déjà définie dans la fonction, c'est également un noop en ce qui concerne les noms importés de l'objet! Une petite tête sur le nom en cours de définition le rendrait beaucoup plus sûr. Personnellement, je n'utiliserai jamais avec pour cette raison.

17
Gerard ONeill

J'ai constaté que beaucoup de personnes qui découvraient JavaScript avaient du mal à comprendre que l'héritage est disponible par défaut dans le langage et que l'étendue de la fonction est la seule étendue jusqu'à présent. J'ai fourni une extension à une esthéticienne que j'ai écrite à la fin de l'année dernière et qui s'appelle JSPretty. La fonction de couleurs de fonction porte dans le code et associe 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 portée est utilisée dans une portée différente.

Essayez la fonctionnalité à:

Voir une démo à:

Voir le code à:

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

10
austincheney

JavaScript n'a que deux types d'étendue:

  1. Global Scope: Global n'est rien d'autre qu'une portée au niveau de la fenêtre. Ici, la variable est présente dans toute l'application.
  2. Portée fonctionnelle: La variable déclarée dans une fonction avec le mot clé var 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), suivi de variables en JavaScript.

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

Chaîne de portée ->

  1. Niveau de la fenêtre - Les fonctions a et outer sont au premier niveau de la chaîne de l'oscilloscope.
  2. lorsque la fonction externe appelle un nouveau variable scope object (et est inclus dans la chaîne d'étendue) ajouté avec la variable b à l'intérieur.

Désormais, lorsqu'une variable a est requise, elle recherche d'abord la portée de la variable la plus proche. Si variable n'est pas présente, elle est déplacée vers le prochain objet de la chaîne de portée de la variable. Dans ce cas, elle est au niveau de la fenêtre.

9
Anshul

Pour ajouter aux autres réponses, scope est une liste de recherche de tous les identificateurs déclarés (variables), et applique un ensemble de règles strictes concernant la manière dont ils sont accessibles au code en cours d'exécution. Cette recherche peut avoir pour objectif d'affecter la variable, qui est une référence LHS (côté gauche), ou de récupérer sa valeur, qui est une référence RHS (côté droit). Le moteur JavaScript effectue ces recherches en interne lors de la compilation et de l’exécution du code.

Donc, de ce point de vue, je pense qu’une image qui pourrait aider ce que j’ai trouvé dans le livre numérique Scopes and Closures de Kyle Simpson:

image

Citant son livre électronique:

Le bâtiment représente le jeu de règles de portée imbriquée de notre programme. Le premier étage du bâtiment représente votre portée actuellement en cours d’exécution, où que vous soyez. Le niveau supérieur du bâtiment est la portée globale. Vous résolvez les références LHS et RHS en regardant sur votre étage actuel, et si vous ne le trouvez pas, prenez l’ascenseur jusqu’à l’étage suivant, regardez là, puis le suivant, et ainsi de suite. Une fois que vous arrivez au dernier étage (la portée mondiale), vous trouvez ce que vous recherchez ou vous ne le faites pas. Mais vous devez vous arrêter quand même.

Il convient de mentionner une chose importante à noter: "La recherche dans Scope s'arrête une fois la première correspondance trouvée".

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 vers tous ces détails, Tout ce que vous vouliez savoir sur la portée de javascript

9
James Drinkard

Portée globale:

Les variables globales sont exactement comme les stars globales (Jackie Chan, Nelson Mandela). Vous pouvez y accéder (obtenir ou définir la valeur) depuis n’importe quelle partie de votre application. Les fonctions globales ressemblent aux é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 d’une manière ou d’une autre à faire les tabloïds). Mais les gens en dehors des États-Unis ne la reconnaîtront pas. Elle est une star locale, liée à son territoire.

Les variables locales ressemblent aux étoiles locales. Vous pouvez uniquement y accéder (obtenir ou définir la valeur) à l'intérieur de la portée. Une fonction locale ressemble aux événements locaux: vous ne pouvez exécuter que (célébrer) à l'intérieur de cette étendue. Si vous souhaitez y accéder de 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

8
KhanSharp

lancez 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);
8
Yeasin Abedin Siam

Il n’existe presque que deux types d’étendues JavaScript:

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

Ainsi, les blocs autres que les fonctions ne créent pas de nouvelle portée. Cela explique pourquoi les boucles for remplacent les variables étendues 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 et les variables initialement déclarées ont été écrasées. Dans le deuxième exemple, il y avait une nouvelle portée due à la fonction. Les variables initialement déclarées étaient donc ombragées et non écrasées.

C'est presque tout ce que vous devez savoir sur la portée de JavaScript, à l'exception de:

La portée de JavaScript est donc extrêmement simple, mais pas toujours intuitive. Quelques choses à prendre en compte:

  • les déclarations var sont hissées en haut de la portée. Cela signifie que peu importe où la déclaration var se produit, pour le compilateur, c'est comme si la var elle-même arrivait en haut
  • plusieurs déclarations var dans la même portée 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 cela a du sens du point de vue d’un concepteur de langage impératif.

6
jackbean818

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

Vous devriez utiliser la portée de bloc pour chaque variable que vous créez, comme dans la plupart des autres langues principales. var est obsolète . Cela rend votre code plus sûr et plus facile à gérer.

const devrait être utilisé pour 95% des cas. Ainsi, la variable référence ne peut pas changer. Les propriétés de tableau, d'objet et de nœud DOM peuvent changer et devraient probablement être const.

let devrait être utilisé pour toute variable devant être réaffectée. Cela inclut dans une boucle for. Si vous modifiez une valeur au-delà de l'initialisation, utilisez let.

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 portées internes, y compris les fonctions anonymes créées dans votre portée.

5
Gibolt

Il n'y a que des portées de fonctions dans JS. Pas bloquer les portées! Vous pouvez aussi voir ce qui se lève.

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);
4
koredalin

D'après ce que je comprends, il y a 3 champs d'application: le champ d'application mondial, disponible dans le monde entier; portée locale, disponible pour une fonction entière indépendamment des blocs; et portée de bloc, disponible uniquement pour le bloc, l'instruction ou l'expression sur laquelle il a été utilisé. Les étendues globale et locale sont indiquées avec le mot clé 'var', dans une fonction ou en dehors, et la portée de bloc est indiquée avec 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

3
mrmaclean89

Essayez cet exemple curieux. Dans l'exemple ci-dessous, si a était un chiffre initialisé à 0, vous verriez 0, puis 1. Sauf que a est un objet et que javascript passera f1 un pointeur d'un plutôt que d'une copie de celui-ci. Le résultat est que vous recevez 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());
3
Mig82

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

  • Portée locale
  • Portée globale

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 inférieure 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 
    }
}
2
Abdur Rahman

ES5 et antérieur:

Les variables en Javascript étaient initialement (pré ES6) fonctionnelles de manière lexicale. Le terme périmé lexicalement signifie que vous pouvez voir la portée des variables en "regardant" le code.

Chaque variable déclarée avec le mot clé var est étendue à la fonction. Cependant, si d'autres fonctions sont déclarées dans cette fonction, celles-ci auront accès aux variables des fonctions externes. Ceci s'appelle un 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. C’est le corps de la fonction, c’est-à-dire tout ce qui se trouve entre accolades {} (sauf les variables à l'intérieur de autrefonctions qui sont dans cette étendue).
  2. S'il ne peut pas trouver la variable à l'intérieur du corps de la fonction, il montera jusqu'à la chaîne et examinez la portée de la variable dans la fonction en où la fonction a été définie. C’est ce que l’on entend par portée lexicale, on peut voir dans le code où cette fonction a été définie et donc déterminer la chaîne de la 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 foobar sur la console, comme suit:

  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 avec la chaîne innerFunc.
  2. Nous essayons de connecter barre à la console, barre ne peut pas être trouvée à l'intérieur de la fonction innerFunc lui-même. Par conséquent, nous devons gravir la chaîne de l'oscilloscope. Nous examinons d’abord la fonction externe dans laquelle la fonction innerFunc a été définie. C'est la fonction outerFunc. Dans le cadre de outerFunc, nous pouvons trouver la barre de variable, qui contient la chaîne 'outerFunc'.
  3. foobar ne peut pas être trouvé dans innerFunc. . Par conséquent, nous devons gravir la chaîne de la portée à la portée de innerFunc. On ne peut pas non plus le trouver ici, nous grimpons d'un autre niveau au portée globale (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 gravi la chaîne de l'oscilloscope, le moteur JS lançait un referenceError.

ES6 (ES 2015) et plus ancien:

Les mêmes concepts de portée lexicale et de scopechain s'appliquent toujours dans ES6. Cependant, une nouvelle façon de déclarer les variables a été introduite. Il y a les suivantes:

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

La plus grande différence entre var et let/const est que var est une fonction étendue alors que let/const est une étendue de blocs. Voici un exemple pour illustrer ceci:

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 let ont une portée de 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.

1
Willem van der Veen

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 la portée locale dans les 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
1
Dava

Dans EcmaScript5, il y a principalement deux portées, portée locale et portée globale, mais dans EcmaScript6, nous avons principalement trois portées, la portée locale, la portée globale et une nouvelle portée appelée portée du 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.
}
1
Vivek Mehta