Je viens de lire un excellent article sur JavaScript avec une portée et une hissage de Ben Cherry dans lequel il donne l'exemple suivant:
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
alert(a);
En utilisant le code ci-dessus, le navigateur alertera "1".
Je ne sais toujours pas pourquoi il renvoie "1". Certaines des choses qu’il dit viennent à l’esprit, telles que: Toutes les déclarations de fonctions sont levées vers le haut. Vous pouvez définir une variable à l'aide de la fonction. Ne clique toujours pas pour moi.
Le levage de fonction signifie que les fonctions sont déplacées vers le haut de leur portée. C'est,
function b() {
a = 10;
return;
function a() {}
}
sera réécrit par l'interpètre à cette
function b() {
function a() {}
a = 10;
return;
}
Bizarre, hein?
Aussi, dans ce cas,
function a() {}
s'est comporté comme
var a = function () {};
Donc, en gros, voici ce que fait le code:
var a = 1; //defines "a" in global scope
function b() {
var a = function () {}; //defines "a" in local scope
a = 10; //overwrites local variable "a"
return;
}
b();
alert(a); //alerts global variable "a"
Ce dont vous devez vous souvenir, c’est qu’elle analyse la totalité de la fonction et résout toutes les déclarations de variables avant de l’exécuter. Alors....
function a() {}
devient vraiment
var a = function () {}
var a
le force dans une étendue locale, et la portée de la variable couvre toute la fonction. La variable globale a donc toujours la valeur 1 car vous avez déclaré une dans une étendue locale en la transformant en fonction.
La fonction a
est hissé dans la fonction b
:
var a = 1;
function b() {
function a() {}
a = 10;
return;
}
b();
alert(a);
ce qui revient presque à utiliser var
:
var a = 1;
function b() {
var a = function () {};
a = 10;
return;
}
b();
alert(a);
La fonction est déclarée localement et la définition de a
ne se produit que dans la portée locale, pas dans la variable globale.
function a(){}
est levée en premier et elle se comporte comme var a = function () {};
; ainsi, dans la portée locale a
est créée. a=10
, vous définissez la variable locale a
, pas la variable globale.Par conséquent, la valeur de la variable globale reste la même et vous obtenez, alerté 1
Le levage est un concept conçu pour que nous puissions le comprendre plus facilement. Ce qui se passe réellement, c’est que les déclarations sont faites d’abord en ce qui concerne leur champ d’application et que les assignations auront lieu par la suite (pas au même moment).
Lorsque les déclarations se produisent, var a
, puis function b
et à l'intérieur de cette étendue b
, function a
est déclaré.
Cette fonction a suivra la variable a provenant de la portée globale.
Une fois les déclarations terminées, les valeurs attribuées commenceront, la variable globale a
recevra la valeur 1
et le function b
intérieur obtiendra le 10
. Lorsque vous ferez alert(a)
, il appellera la variable de portée globale réelle. Ce petit changement au code le rendra plus clair
var a = 1;
function b() {
a = 10;
return a;
function a() { }
}
alert(b());
alert(a);
Quelle est la pomme de discorde dans ce petit extrait de code?
Cas 1:
Incluez la définition de function a(){}
dans le corps de function b
comme suit. logs value of a = 1
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
console.log(a); // logs a = 1
Cas 2
Exclure la définition de function a(){}
dans le corps de function b
comme suit. logs value of a = 10
var a = 1;
function b() {
a = 10; // overwrites the value of global 'var a'
return;
}
b();
console.log(a); // logs a = 10
Observation vous aidera à comprendre que la déclaration console.log(a)
enregistre les valeurs suivantes.
Cas 1: a = 1
Cas 2: a = 10
Posits
var a
a été défini et déclaré lexicalement dans la portée globale. a=10
Cette instruction réaffecte la valeur à 10, elle se situe lexicalement dans la fonction b. Explication des deux cas
En raison de function definition with name property
, a est identique à variable a
. Le variable a
à l'intérieur du function body b
devient une variable locale. La ligne précédente implique que la valeur globale de a reste intacte et que la valeur locale de a est mise à jour à 10.
Donc, ce que nous avons l'intention de dire, c'est que le code ci-dessous
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
console.log(a); // logs a = 1
Il est interprété par l’interprète JS comme suit.
var a = 1;
function b() {
function a() {}
a = 10;
return;
}
b();
console.log(a); // logs a = 1
Cependant, lorsque nous supprimons la function a(){} definition
, le value of 'a'
déclaré et défini en dehors de la fonction b, cette valeur est remplacée et remplacée par 10 dans le cas 2. La valeur est écrasée car a=10
fait référence à la déclaration globale et si elle devait être déclarée localement nous devons avoir écrit var a = 10;
.
var a = 1;
function b() {
var a = 10; // here var a is declared and defined locally because it uses a var keyword.
return;
}
b();
console.log(a); // logs a = 1
Nous pouvons clarifier davantage notre doute en remplaçant le name property
dans function a(){} definition
par un autre nom que 'a'
.
var a = 1;
function b() {
a = 10; // here var a is declared and defined locally because it uses a var keyword.
return;
function foo() {}
}
b();
console.log(a); // logs a = 1
scpope & fermeture & levage (var/function)
- scpope: la variable globale peut être accessible n'importe où (le fichier entier scope), seule la variable locale est accessible au local. scope (portée de fonction/bloc)!
Remarque: si une variable locale n'utilise pas var mots-clés dans une fonction, cela deviendra une variable globale!- fermeture: une fonction interne à l'autre fonction à laquelle on peut accéder portée locale (fonction parente) et portée globale, cependant, c’est vars ne peut pas être consulté par d'autres! sauf si, vous le retournez comme valeur de retour!
- levage: déplace tous les declare/undeclare vars/function vers la portée top, que d'affecter la valeur ou null!
Remarque: il suffit de déplacer le déclarer, pas de déplacer la valeur!
var a = 1;
//"a" is global scope
function b() {
var a = function () {};
//"a" is local scope
var x = 12;
//"x" is local scope
a = 10;
//global variable "a" was overwrited by the local variable "a"
console.log("local a =" + a);
return console.log("local x = " + x);
}
b();
// local a =10
// local x = 12
console.log("global a = " + a);
// global a = 1
console.log("can't access local x = \n");
// can't access local x =
console.log(x);
// ReferenceError: x is not defined
function a() { }
est une instruction de fonction qui crée une variable a
locale à la fonction b
.
Les variables sont créées lors de l'analyse d'une fonction, que l'instruction var
ou la fonction soit exécutée.
a = 10
définit cette variable locale.
Tout dépend de la portée de la variable 'a'. Laissez-moi vous expliquer en créant des étendues sous forme d'images.
Ici JavaScript va créer 3 portées.
i) Portée globale . ii) Fonction b() portée . iii) Fonction a() portée.
Il est clair lorsque vous appelez l'étendue de la méthode 'alert' appartient à Global à ce moment-là, donc il choisira la valeur de la variable 'a' dans l'étendue Global uniquement, qui est 1.
Étonnamment, aucune des réponses ici ne mentionne la pertinence du contexte d'exécution dans la chaîne de la portée.
Le moteur JavaScript encapsule le code en cours d'exécution dans un contexte d'exécution. Le contexte d'exécution de base est le contexte d'exécution global. Chaque fois qu'une nouvelle fonction est appelée, un nouveau contexte d'exécution est créé et placé sur la pile d'exécution. Pensez à un cadre de pile assis sur une pile d'invocation dans d'autres langages de programmation. Dernier entré, premier sorti. Désormais, chaque contexte d'exécution a ses propres environnement variable et environnement extérieur en JavaScript.
Je vais utiliser l'exemple ci-dessous à titre de démonstration.
1) Nous entrons d’abord dans la phase de création du contexte d’exécution global. L'environnement extérieur et l'environnement variable de l'environnement lexical sont créés. L'objet global est configuré et mis en mémoire avec la variable spéciale 'this' qui le pointe. La fonction a et son code ainsi que la variable myVar avec une valeur indéfinie sont placés en mémoire dans l'environnement variable global. il est important de noter que le code de la fonction a n'est pas exécuté. Il est juste mis en mémoire avec la fonction a.
2) Deuxièmement, il s’agit de la phase d’exécution du contexte d’exécution. myVar n'est plus une valeur indéfinie. Il est initialisé avec la valeur 1, qui est stockée dans l'environnement variable global. La fonction a est appelée et un nouveau contexte d'exécution est créé.
3) Dans le contexte d'exécution de la fonction a, il passe par la phase de création et d'exécution de son propre contexte d'exécution. Il possède son propre environnement extérieur et son environnement variable, donc son propre environnement lexical. La fonction b et la variable myVar sont stockées dans son environnement variable. Cet environnement variable est distinct de l'environnement variable global. Etant donné que la fonction est située de manière lexicale (physiquement dans le code) au même niveau que le contexte d'exécution global, son environnement externe est le contexte d'exécution global. Ainsi, si la fonction a devait faire référence à une variable qui ne se trouve pas dans son environnement de variable, elle recherchera la chaîne d'étendue et tentera de trouver la variable dans l'environnement de variable du contexte global d'exécution.
4) La fonction b est appelée dans la fonction a. Un nouveau contexte d'exécution est créé. Comme il a une fonction lexicale en tant que fonction a, son environnement extérieur est un. Ainsi, lorsqu'il fait référence à myVar, puisque myVar ne se trouve pas dans l'environnement variable de la fonction b, il recherche l'environnement variable de la fonction a. Il le trouve à cet emplacement et console.log en imprime 2. Mais si la variable n'était pas dans l'environnement variable de la fonction a, étant donné que l'environnement extérieur de la fonction a est le contexte d'exécution global, la chaîne d'étendues poursuivra la recherche.
5) Une fois l'exécution des fonctions b et a terminée, elles sont extraites de la pile d'exécution. Le moteur JavaScript à un seul thread continue l'exécution au contexte global d'exécution. Il appelle la fonction b. Mais il n'y a pas de fonction b dans l'environnement variable global et il n'y a pas d'autre environnement extérieur à rechercher dans le contexte d'exécution global. Ainsi, une exception est déclenchée par le moteur JavaScript.
function a(){
function b(){
console.log(myVar);
}
var myVar = 2;
b();
}
var myVar = 1;
a();
b();
> 2
> Uncaught ReferenceError: b is not defined
L'exemple ci-dessous montre la chaîne Scope en action. Dans l'environnement variable du contexte d'exécution de la fonction b, il n'y a pas myVar. Donc, il recherche son environnement externe, qui est la fonction a. La fonction a n'a pas non plus myVar dans son environnement variable. Ainsi, le moteur recherche l'environnement externe de la fonction a, qui est l'environnement externe du contexte d'exécution global et myVar y est défini. Par conséquent, le fichier console.log affiche 1.
function a(){
function b(){
console.log(myVar);
}
b();
}
var myVar = 1;
a();
> 1
Concernant le contexte d’exécution et l’environnement lexical qui lui est associé, notamment l’environnement externe et l’environnement variable, permettent de définir la portée des variables en JavaScript. Même si vous appelez la même fonction plusieurs fois, pour chaque appel, il créera son propre contexte d'exécution. Ainsi, chaque contexte d’exécution aura sa propre copie des variables dans son environnement de variables. Il n'y a pas de partage de variables.
Voici mon récapitulatif de la réponse avec plus d'annotation et un violon accompagnant à jouer.
// hoisting_example.js
// top of scope ie. global var a = 1
var a = 1;
// new scope due to js' functional (not block) level scope
function b() {
a = 10; // if the function 'a' didn't exist in this scope, global a = 10
return; // the return illustrates that function 'a' is hoisted to top
function a(){}; // 'a' will be hoisted to top as var a = function(){};
}
// exec 'b' and you would expect to see a = 10 in subsequent alert
// but the interpreter acutally 'hoisted' the function 'a' within 'b'
// and in doing so, created a new named variable 'a'
// which is a function within b's scope
b();
// a will alert 1, see comment above
alert(a);
D'après mes connaissances, le levage se produit avec la déclaration de variable et la déclaration de fonction, par exemple:
a = 7;
var a;
console.log(a)
Que se passe-t-il dans le moteur de JavaScript?
var a;
a = 7;
console.log(a);
// 7
Ou:
console.log(square(7)); // Output: 49
function square(n) { return n * n; }
Il deviendra:
function square(n) { return n * n; }
console.log(square(7)); // 49
Mais les affectations telles que l’affectation de variable, l’affectation d’expression de fonction ne seront pas levées: Par exemple:
console.log(x);
var x = 7; // undefined
Cela peut devenir comme ça:
var x;
console.log(x); // undefined
x = 7;
Cela se produit parce que le nom de la variable est identique au nom de la fonction qui signifie "a" . Donc, en raison de son transfert par Javascript, essayez de résoudre le conflit de nommage et il retournera a = 1.
J'étais aussi confus à ce sujet jusqu'à ce que je lise ce billet sur "JavaScript Hoisting" http://www.ufthelp.com/2014/11/JavaScript-Hoisting.html
J'espère que ça aide.
Long Post!
Mais ça va effacer l'air!
Le fonctionnement de Java Script consiste en un processus en deux étapes:
Compilation (pour ainsi dire) - Cette étape enregistre les variables et les déclarations de fonction et leur portée respective. Cela n'implique pas l'évaluation de l'expression de fonction: var a = function(){}
ou d'une expression de variable (comme l'affectation de 3
à x
dans le cas de var x =3;
qui n'est rien d'autre que l'évaluation de la partie R.H.S.)
Interprète: Ceci est la partie exécution/évaluation.
Vérifiez la sortie du code ci-dessous pour comprendre:
//b() can be called here!
//c() cannot be called.
console.log("a is " + a);
console.log("b is " + b);
console.log("c is " + c);
var a = 1;
console.log("Now, a is " + a);
var c = function() {};
console.log("Now c is " + c);
function b() {
//cannot write the below line:
//console.log(e);
//since e is not declared.
e = 10; //Java script interpreter after traversing from this function scope chain to global scope, is unable to find this variable and eventually initialises it with value 10 in global scope.
console.log("e is " + e) // works!
console.log("f is " + f);
var f = 7;
console.log("Now f is " + f);
console.log("d is " + d);
return;
function d() {}
}
b();
console.log(a);
Permet de le casser:
Lors de la phase de compilation, 'A' serait enregistré sous un périmètre global avec la valeur 'undefined
'. Il en va de même pour 'c
', sa valeur à ce moment serait 'undefined
' et non la 'function()
'. 'b
'serait enregistré en tant que fonction dans la portée globale. Dans la portée de b
, 'f
' serait enregistré en tant que variable qui serait indéfinie pour le moment et la fonction 'd
' serait enregistrée.
Lorsque l'interpréteur s'exécute, les variables déclarées et function()
(et non les expressions) sont accessibles avant que l'interpréteur n'atteigne la ligne d'expression réelle. Ainsi, les variables seraient imprimées 'undefined
' et la fonction déclarée anonyme pourrait être appelée plus tôt. Cependant, essayer d'accéder à une variable non déclarée avant son initialisation d'expression entraînerait une erreur du type:
console.log(e)
e = 3;
Maintenant, que se passe-t-il lorsque vous avez une déclaration de variable et de fonction portant le même nom?
La réponse est - les fonctions sont toujours levées avant et si la même variable de nom est déclarée, elle est traitée comme une copie et est ignorée. Rappelez-vous, l'ordre n'a pas d'importance. Les fonctions ont toujours la priorité. Mais pendant la phase d'évaluation, vous pouvez changer la référence de variable à n'importe quoi (il stocke tout ce qui était la dernière affectation) Regardez le code ci-dessous:
var a = 1;
console.log("a is " + a);
function b() {
console.log("a inside the function b is " + a); //interpreter finds 'a' as function() in current scope. No need to go outside the scope to find 'a'.
a = 3; //a changed
console.log("Now a is " + a);
return;
function a() {}
}
var a; //treated as duplicate and ignored.
b();
console.log("a is still " + a + " in global scope"); //This is global scope a.
Levage En JavaScript, les déclarations de variable sont exécutées tout au long du programme avant l'exécution du code. Par conséquent, déclarer une variable n'importe où dans le code équivaut à le déclarer au début.
Le levage est un concept comportemental de JavaScript. Le levage (par exemple le déplacement) est un concept qui explique comment et où les variables doivent être déclarées.
En JavaScript, une variable peut être déclarée après avoir été utilisée car les déclarations de fonction et les déclarations de variable sont toujours déplacées ("levées") de manière invisible vers le haut de la portée qu'elles contiennent par l'interpréteur JavaScript.
Nous rencontrons deux types de levage dans la plupart des cas.
1. déclaration de levage variable
Permet de comprendre cela par ce morceau de code.
a = 5; // Assign 5 to a
elem = document.getElementById("demo"); // Find an element
elem.innerHTML = a; // Display a in the element
var a; // Declare a
//output-> 5
Ici, la déclaration de la variable a sera hébergée de manière invisible par l’interprète javascript au moment de la compilation. Nous avons donc pu obtenir une valeur de a. Mais cette approche de déclaration de variables n'est pas recommandée car nous devrions déjà déclarer les variables en haut de cette façon.
var a = 5; // Assign and declare 5 to a
elem = document.getElementById("demo"); // Find an element
elem.innerHTML = a; // Display a in the element
// output -> 5
considérons un autre exemple.
function foo() {
console.log(x)
var x = 1;
}
est en fait interprété comme ceci:
function foo() {
var x;
console.log(x)
x = 1;
}
Dans ce cas, x sera indéfini
Peu importe si le code exécuté contient la déclaration de variable. Considérons cet exemple.
function foo() {
if (false) {
var a = 1;
}
return;
var b = 1;
}
Cette fonction s'avère être comme ça.
function foo() {
var a, b;
if (false) {
a = 1;
}
return;
b = 1;
}
Dans la déclaration de variable, seuls les palans à définition de variable, pas l'affectation.
Contrairement à la variable soulevant le corps de la fonction, la valeur assignée sera également levée. Considérons ce code
function demo() {
foo(); // this will give error because it is variable hoisting
bar(); // "this will run!" as it is function hoisting
var foo = function () {
alert("this would not run!!");
}
function bar() {
alert("this will run!!");
}
}
demo();
Maintenant que nous avons compris le levage de variables et de fonctions, comprenons maintenant ce code.
var a = 1;
function b() {
a = 10;
return;
function a() {}
}
b();
alert(a);
Ce code sera comme ça.
var a = 1; //defines "a" in global scope
function b() {
var a = function () {}; //defines "a" in local scope
a = 10; //overwrites local variable "a"
return;
}
b();
alert(a);
La fonction a() aura une portée locale à l'intérieur de b (). a() sera déplacé en haut tout en interprétant le code avec sa définition (uniquement en cas de levage de fonction), de sorte qu'un maintenant aura une portée locale et n'affectera donc pas la portée globale d'un temps ayant sa propre portée à l'intérieur fonction b ().