Quelle est la portée des variables dans JavaScript?
Quelle est la portée des variables dans javascript? Ont-ils la même portée à l'intérieur qu'à l'extérieur d'une fonction? Ou faut-il le même problème? En outre, Où sont stockées les variables si elles sont définies globalement?
26 réponses
je pense que le mieux que je puisse faire est de vous donner un tas d'exemples à étudier. Les programmeurs Javascript sont pratiquement classés selon leur compréhension de la portée. Il peut parfois être très contre-intuitif.
-
a variable de portée mondiale
// global scope var a = 1; function one() { alert(a); // alerts '1' }
-
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' }
-
Intermédiaire : Pas une telle chose comme le bloc de portée en JavaScript (ES5; ES6 introduit
let
)un.
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 }
-
Intermédiaire : propriétés de l'Objet
var a = 1; function Five() { this.a = 5; } alert(new Five().a); // alerts '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' }; })();
-
Avancé : basé sur des Prototypes de résolution de portée
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'
-
Global+Local : Un supplément de Cas complexes
var x = 5; (function () { console.log(x); var x = 10; console.log(x); })();
This imprimera
undefined
et10
plutôt que5
et10
car JavaScript déplace toujours les déclarations variables (pas les initialisations) vers le haut de la portée, ce qui rend le code équivalent à:var x = 5; (function () { var x; console.log(x); x = 10; console.log(x); })();
-
clause Catch d'étendue variable
var e = 5; console.log(e); try { throw 6; } catch (e) { console.log(e); } console.log(e);
ce sera imprimé
5
,6
,5
. À l'intérieur de la clause de sauvegardee
les ombres des variables globales et locales. Mais cette portée spéciale ne s'applique qu'à la variable capturée. Si vous écrivezvar f;
dans la clause catch, alors c'est exactement la même chose que si vous l'aviez définie avant ou après le bloc try-catch.
Javascript utilise des chaînes de portée pour établir la portée d'une fonction donnée. Il y a généralement une portée globale, et chaque fonction a son propre imbriquée porté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 scope est essentiellement une carte avec un pointeur vers son scope parent.
lors de la résolution d'un variable, javascript commence au niveau le plus proche et recherche vers l'extérieur.
les Variables déclarées globalement ont une portée globale. Les Variables déclarées dans une fonction sont scopées à cette fonction, et les variables globales de l'ombre du même nom.
(je suis sûr qu'il y a beaucoup de subtilités que les vrais programmeurs JavaScript seront en mesure de souligner dans d'autres réponses. En particulier, je suis tombé sur cette page sur ce que signifie exactement this
à tout moment. Avec un peu de chance ce lien plus introductif est assez pour vous obtenir a commencé.)
Old school JavaScript
traditionnellement, le JavaScript n'a que deux types de portée :
- global Scope : les Variables sont connues tout au long de l'application, dès le début de l'application (*)
- portée fonctionnelle : les Variables sont connues dans la fonction ils sont déclarés dans, dès le début de la fonction (*)
Je ne m'étendrai pas là-dessus, car il y a déjà beaucoup d'autres réponses expliquant la différence.
Moderne JavaScript
le spécifications JavaScript les plus récentes permettent maintenant aussi une troisième portée:
- champ D'application du bloc : les Variables sont connues sous le nom de le bloc elles sont déclarées à partir du moment où elles sont déclarées (**)
comment créer des variables de champ de bloc?
traditionnellement, vous créez vos variables comme ceci:
var myVariable = "Some text";
champ D'application du bloc les variables sont créées comme ceci:
let myVariable = "Some text";
Quelle est donc la différence entre la portée fonctionnelle et la portée globale?
pour comprendre la différence entre la portée fonctionnelle et la portée de 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
est seulement connu dans le premier pour boucle, mais pas avant et après. Pourtant, notre variable i
est connu dans l'ensemble de la fonction.
aussi, considérer que les variables de bloc scoped ne sont pas connus avant qu'ils soient déclarés parce qu'ils ne sont pas hissés. Vous n'êtes pas non plus autorisé à faire une nouvelle sélection de la même variable à l'intérieur du 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 hissées et qui ne produisent pas d'erreurs dans le cas de déclarations multiples.
Est-il sécuritaire d'utiliser le bloc de portée des variables d'aujourd'hui?
qu'il soit sûr ou non d'utiliser aujourd'hui, dépend de votre environnement:
-
si vous écrivez un code JavaScript côté serveur ( noeud.js ), vous pouvez utiliser en toute sécurité la déclaration
let
. -
si vous écrivez un code JavaScript côté client et utilisez un transpirateur (comme Traceur ), vous pouvez utiliser en toute sécurité la déclaration
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 que vous n'utilisez pas de transpirateur, vous devez considérer le support du navigateur.
Aujourd'hui, 23 février 2016, ce sont certains navigateurs qui ne prennent pas en charge
let
ou n'ont qu'un soutien partiel:- Internet explorer 10 et en dessous (pas de support)
- Firefox 43 et en dessous (pas de support)
- Safari 9 et en dessous (pas de support)
- Opera Mini 8 et en dessous (pas de support)
- navigateur Android 4 et ci-dessous (sans support)
- Opéra 36 et ci-dessous (prise en charge partielle)
- Chome 51 et ci-dessous (prise en charge partielle)
Comment garder une trace de la prise en charge du navigateur
pour un aperçu actualisé dont les navigateurs prennent en charge la déclaration let
au moment de la lecture de cette réponse, voir cette 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 hissées . Cela signifie que les déclarations sont toujours bien au-dessus de la portée.
(**) les variables à portée de bloc ne sont pas hissées
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 comment les utiliser pour faire private members .
la clé, telle que je la comprends, est que Javascript a la détermination de la portée au niveau de la fonction par rapport au bloc C le plus commun.
dans "Javascript 1.7" (extension de Mozilla à Javascript) on peut aussi déclarer des variables de block-scope avec let
statement :
var a = 4;
let (a = 3) {
alert(a); // 3
}
alert(a); // 4
l'idée d'établir la portée en JavaScript lorsqu'elle a été conçue à l'origine par Brendan Eich vient du HyperCard langage de script HyperTalk .
dans cette langue, les affichages étaient semblables à une pile de cartes index. Il y avait une carte maîtresse appelée background. Il était transparent et peut être vu comme la carte du bas. Tout le contenu de cette carte de base a été partagé avec les cartes placées sur haut de il. Chaque carte placée sur le dessus avait son propre contenu qui a pris la priorité sur la carte précédente, mais avait tout de même accès aux cartes précédentes si vous le souhaitez.
C'est exactement comme cela que le système JavaScript scoping 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 cette liaison. Pour en revenir à la référence cards, l'environnement lexical contient tout le contenu des cartes précédentes en bas de la pile. Le contexte actuel est en haut de la pile et tout contenu déclaré sera stocké dans l'environnement variable. L'environnement variable aura préséance en cas de collision nommante.
cette reliure indiquera l'objet contenant. Parfois les portées ou les contextes d'exécution changent sans que l'objet contenant change, comme dans une fonction déclarée où l'objet contenant peut être window
ou une fonction de constructeur.
ces contextes d'exécution sont créés à tout moment. 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.
telle est donc l'explication technique. En pratique, il est important de se rappeler que dans JavaScript
- les portées 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 a priorité (le bas étant le contexte global)
- chaque fonction crée un contexte d'exécution (mais pas toujours nouveau)
application à l'un des exemples précédents (5. "Fermeture") sur cette page, c'est possibilité 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 invoquée appelée par var six, et le contexte dans la fonction retournée à l'intérieur de la fonction immédiatement invoquée de var six.
je ) à L'extérieur du contexte. Il a un environnement variable d'un = 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 la fonction retournée, il a un environnement lexical de a = 6 et c'est la valeur référencée dans l'alerte lorsqu'elle est appelée.
1) Il y a un champ d'Application global, un champ d'application de fonction, et le champ d'application with ET catch. Il n'y a pas de portée de niveau' block ' en général pour les variables -- les instructions with et catch ajoutent des noms à leurs blocks.
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 apporte de la propriété de l'objet de noms dans la portée lexicale définie par le bloc.
EDIT: ECMAAScript 6 (Harmony) est spécifié pour supporter let, et je sais que chrome permet un drapeau 'harmony', donc peut-être qu'il le supporte..
Laissez serait un support pour bloc de portée au niveau, mais vous devez utiliser le mot clé pour y arriver.
EDIT: Basé sur Benjamin de pointage de la avec et instructions catch dans les commentaires, j'ai édité le post, et a ajouté plus. Les deux la avec et les instructions catch introduire des variables dans leurs blocs respectifs, et que est une portée de bloc. Ces variables sont aliasées aux propriétés des objets qui y 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: Clarifier exemple:
test 1 est scopé au bloc avec, mais est aliasé au bloc A. test 1. 'Var test1' crée une nouvelle variable test1 dans le contexte lexical supérieur (fonction, ou global), à moins qu'elle ne soit une propriété d'un -- ce qu'elle est.
Beurk! Être attention en utilisant 'with' -- 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 m'en servirai jamais à cause de ça.
j'ai trouvé que beaucoup de gens nouveaux à 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 plus beau que j'ai écrit à la fin de l'année dernière appelé JSPretty. La fonctionnalité couleurs Fonction portée dans le code et associe toujours une couleur à toutes les variables déclarées dans cette portée. La fermeture est visuellement démontrée quand une variable avec une couleur d'une portée est utilisée dans un différent portée.
Essayez de la fonction:
voir une démo à:
visualiser le code:
- http://prettydiff.com/lib/jspretty.js
- https://github.com/austincheney/Pretty-Diff/blob/master/lib/jspretty.js
actuellement, la fonctionnalité offre un support pour une profondeur de 16 fonctions imbriquées, mais ne colore pas les variables globales.
JavaScript n'ont que deux type de portée :
- de Portée Mondiale : Global n'est rien mais une fenêtre au niveau de la portée.Ici, variable présente tout au long de l'application.
- portée fonctionnelle : Variable déclarée dans une fonction avec
var
le mot-clé a une portée fonctionnelle.
chaque fois qu'une fonction est appelée, une portée variable objet est créé (et inclus dans la chaîne scope) qui est suivi de variables en JavaScript.
a = "global";
function outer(){
b = "local";
console.log(a+b); //"globallocal"
}
outer();
la Portée de la chaîne -->
- niveau de fenêtre -
a
etouter
fonction sont au niveau supérieur dans la chaîne de portée. - lorsque la fonction externe appelle un nouveau
variable scope object
(et inclus dans la chaîne scope) ajouté avec la variableb
à l'intérieur.
maintenant quand un la variable a
a exigé qu'il cherche d'abord pour la variable portée la plus proche et si la variable n'est pas là qu'il se déplace à l'objet suivant de la chaîne de portée variable.qui est dans ce cas est le niveau de la fenêtre.
juste 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 quant à la façon dont ceux-ci sont accessibles au code en cours d'exécution. Cette recherche peut avoir pour but d'attribuer à la variable, qui est une référence LHS (à gauche), ou elle peut avoir pour but de retrouver sa valeur, qui est une référence RHS (à droite). Ces recherches sont ce que le moteur JavaScript fait à l'interne quand il est compiler et exécuter le code.
donc, de ce point de vue, je pense qu'une image serait utile que j'ai trouvé dans les lunettes et les fermetures ebook par Kyle Simpson:
citant son ebook:
le bâtiment représente les règles de portée imbriquées de notre programme. Première étage du bâtiment représente votre champ d'application 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 plancher actuel, et si vous ne le trouvez pas, prenez l'ascenseur à l'étage suivant, en regardant là, puis le suivant, et ainsi de suite. Une fois que vous obtenez à l'étage supérieur (la portée mondiale), soit vous trouver ce que vous cherchez, ou vous ne le fais pas. Mais tu dois arrêter de toute façon.
Une chose de la note qui vaut la peine de mentionner, "Champ de recherche s'arrête une fois qu'il trouve le premier match".
cette idée de" niveaux de portée "explique pourquoi" ceci " peut être changé avec une portée nouvellement créée, si elle est recherchée dans une fonction imbriquée. Voici un lien qui va dans tous ces détails, Tout ce que vous vouliez savoir à propos de JavaScript scope "151980920
lancez le code. espérons que cela donnera une idée sur l'étendue des
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);
Portée Mondiale:
variables Globales sont exactement comme des stars mondiales (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 globaux (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 Etats - Unis, vous connaissez peut-être Kim Kardashian, célèbre célébrité ( elle d'une manière ou d'une autre réussit à faire les tabloïds). Mais les gens en dehors des USA ne la reconnaîtront pas. Elle est une star locale, liée à son territoire.
les variables locales sont comme les étoiles locales. Vous ne pouvez y accéder (obtenir ou définir la valeur) qu'à l'intérieur du scope. Une fonction locale est comme des événements locaux - vous pouvez exécuter seulement (celebrate) à l'intérieur de cette portée. Si vous voulez 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
Vérifiez cet article pour une compréhension approfondie de la portée
il n'y a presque que deux types de portées JavaScript:
- le champ d'application de chaque déclaration var est associé à la fonction la plus immédiatement enveloppante
- s'il n'y a pas de fonction enveloppante pour une déclaration var, c'est la portée globale
ainsi, les blocs autres que les fonctions ne créent pas une nouvelle portée. Cela explique pourquoi les for-loops écrasent les variables externes scopées:
var i = 10, v = 10;
for (var i = 0; i < 5; i++) { var v = 5; }
console.log(i, v);
// output 5 5
utilisant 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 champ d'application de bloc, de sorte que les variables initialement déclarées ont été écrasées. Dans le second exemple, il y avait une nouvelle portée due à la fonction, de sorte que les variables initialement déclarées étaient ombrées, et non écrasées.
C'est presque tout ce que vous devez savoir en termes de portée JavaScript, sauf:
- try/catch introduire de nouveaux portée SEULEMENT pour la variable d'exception elle-même, d'autres variables n'ont pas de nouvelle portée
- avec la clause apparemment est une autre exception, mais avec l'aide de la clause, il est hautement déconseillée ( https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with )
donc vous pouvez voir que JavaScript scoping est en fait extrêmement simple, bien que pas toujours intuitif. Quelques éléments à prendre en compte:
- Les déclarations
- var sont hissées au sommet de la portée. Cela signifie que peu importe où la déclaration var se produit, pour le compilateur c'est comme si le var lui-même se produit au sommet
- plusieurs déclarations var dans le même champ d'application sont combinées
donc ce code:
var i = 1;
function abc() {
i = 2;
var i = 3;
}
console.log(i); // outputs 1
est l'équivalent de:
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 a du sens à partir de la point de vue d'un langage impératif designer.
Moderne Js, ES6+, ' const
" et " let
'
vous devriez utiliser la détermination de la portée de bloc pour chaque variable que vous créez, tout comme la plupart des autres langues principales. var
est obsolète . Cela rend votre code plus sûr et plus maintenable.
const
doit être utilisé pour 95% des cas . Il le rend donc la variable référence ne peut pas changer. Tableau, les propriétés des objets et des noeuds DOM peuvent changer et devraient probablement être const
.
let
doit être utilisé pour toute variable devant être réaffectée. Ceci inclut dans une boucle for. Si vous changez de valeur au-delà de l'initialisation, utilisez let
.
champ D'application de bloc signifie que la variable ne sera disponible que dans les parenthèses dans lesquelles elle est déclarée. Cela s'étend aux portées internes, y compris les fonctions anonymes créées dans votre portée.
il n'y a que des portées de fonction dans JS. Ne pas bloquer les étendues! Vous pouvez voir ce qui hisse aussi.
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);
chaque morceau de code JavaScript (global code ou fonctions) est associé à une chaîne scope. Ce champ d'application
la chaîne est une liste ou une chaîne d'objets qui définit les variables qui sont dans la portée que
code. Quand JavaScript doit chercher la valeur d'une variable x
(un processus appelé
résolution variable ), il commence par regarder le premier objet de la chaîne. Si cet objet a
un bien nommé x
, la valeur de ce bien est utilisé. Si le premier objet n'a pas
une propriété nommée x
, JavaScript continue la recherche avec l'objet suivant dans la chaîne.
Si le second objet n'a pas de propriété nommée x
, la recherche passe à la suivante
objet, et ainsi de suite. Si x
n'est la propriété d'aucun des objets de la chaîne scope, alors
x
n'entre pas dans le champ d'application de ce code, et une erreur de référence se produit.
Dans le code JavaScript de haut niveau (c.-à-d., code Non contenu dans une fonction définition),
la chaîne scope se compose d'un seul objet, l'objet global. Dans une fonction non imbriquée,
la chaîne scope se compose de deux objets. La première est l'objet qui définit la fonction
paramètres et variables locales, et la seconde est l'objet global. Dans une fonction imbriquée,
la chaîne scope a trois objets ou plus. Il est important de comprendre comment cette chaîne
des objets est créé. Quand une fonction est défini , il stocke la chaîne de portée puis dans effet.
Lorsque cette fonction est invoquée , elle crée un nouvel objet pour stocker ses variables locales, et
Ajoute ce nouvel objet à la chaîne scope stockée pour créer une nouvelle chaîne plus longue
représente la portée de l'invocation de cette fonction. Cela devient plus intéressant pour
fonctions imbriquées parce que chaque fois que la fonction externe est appelée, la fonction interne est
définies à nouveau. Puisque la chaîne scope diffère sur chaque invocation de la fonction externe,
la fonction interne sera subtilement différent chaque fois qu'il est défini-le code de l'intérieur
fonction sera identique sur chaque invocation de la fonction externe, mais la chaîne de portée
associée à ce code sera différent .
Cette notion de chaîne de portée est essentielle pour comprendre les fermetures .
Essayez ce curieux exemple. Dans l'exemple ci-dessous si un ont un numérique initialisé à 0, vous verriez 0 et 1. Sauf un est un objet javascript va passer f1 un pointeur d'une 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());
ma compréhension est qu'il y a 3 portées: portée globale, disponible à l'échelle mondiale; portée locale, disponible pour une fonction entière indépendamment des blocs; et portée de bloc, disponible seulement pour le bloc, la déclaration, ou l'expression sur laquelle il a été utilisé. La portée globale et locale est indiquée par le mot-clé 'var', que ce soit à l'intérieur d'une fonction ou à l'extérieur, et la portée de bloc est indiquée par le mot-clé 'let'.
Pour ceux qui croient, il est seulement mondiale et locale, veuillez expliquez pourquoi Mozilla aurait une page entière décrivant les nuances de la portée de bloc dans JS.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
en JavaScript il y a deux types de champ d'application:
- Locale
- portée mondiale
la fonction ci-dessous a une variable de portée locale carName
. Et cette variable n'est pas accessible depuis 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
}
}
Dans EcmaScript5, il y a principalement deux étendues, locale et de portée mondiale mais dans EcmaScript6 nous avons principalement trois domaines, de portée locale, de portée mondiale et un nouveau champ appelé bloc de portée .
exemple de champ d'application du 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.
}
ECMAScript 6 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 soutiennent la déclaration de portée locale à l'intérieur des énoncés 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
ES5
et plus:
les Variables en Javascript ont été initialement (pré ES6
) la fonction lexique scoped. Le terme lexicalement scopé 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 scopée à la fonction. Toutefois, si d'autres fonctions sont déclarées à l'intérieur de cette fonction de ces fonctions auront accès à des variables de l'extérieur fonction. C'est ce qu'on appelle une chaîne de portée . Il fonctionne de la manière suivante:
- Lorsqu'une fonction cherche à résoudre une valeur variable, elle regarde d'abord sa propre portée. Il s'agit du corps de la fonction, c'est-à-dire tout ce qui se trouve entre crochets bouclés {} (à l'exception des variables à l'intérieur de autres fonctions qui relèvent de ce champ).
- S'il ne trouve pas la variable dans le le corps de la fonction il grimpera jusqu'à la chaîne et regarder la portée variable dans la fonction dans où la fonction a été définie . C'est ce qu'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 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();
Ce qui arrive quand nous essayez d'enregistrer les variables foo
, bar
, et foobar
sur la console est le suivant:
- nous essayons de connecter foo à la console, foo peut être trouvé à l'intérieur de la fonction
innerFunc
elle-même. Par conséquent, la valeur de foo est déterminée par la chaîne de caractèresinnerFunc
. - nous essayons de connecter bar à la console, bar ne peut pas être trouvé à l'intérieur de la fonction
innerFunc
elle-même. Par conséquent, nous devons monter la portée la chaîne . Nous regardons d'abord dans la fonction externe, dans lequel la fonctioninnerFunc
a été défini. C'est la fonctionouterFunc
. Dans le champ d'application deouterFunc
nous pouvons trouver la barre de variables, qui contient la chaîne de caractères "outerFunc". - foobar ne se trouve pas dans innerFunc. . Par conséquent, nous devons grimper la chaîne de portée à la portée innerFunc. Il ne peut pas non plus être trouvé ici, nous montons un autre niveau à la portée globale (c'est-à-dire la portée extérieure). Nous trouvons ici la variable foobar qui contient la chaîne 'global'. S'il n'avait pas trouvé la variable après avoir escaladé la chaîne scope, le moteur JS lancerait une référence 1519310920".
ES6
(ES 2015) et plus:
Les mêmes concepts de lexicalement portée et scopechain s'appliquent toujours dans ES6
. Toutefois, une nouvelle façon de déclarer les variables a été introduite. Il y a les suivants:
-
let
: crée un bloc de la variable scoped -
const
: crée une variable à portée de bloc qui doit être initialisée et ne peut pas être réattribuée
la plus grande différence entre var
et let
/ const
est que var
est fonction scoped tandis que let
/ const
sont Bloc scoped. 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 parce que les variables déclarées avec let
sont définies par bloc. Ils cessent d'exister en dehors de leur bloc respectif, de sorte que la variable ne peut pas être accessible en dehors du bloc si.
il y a deux types de portées en JavaScript.
-
portée globale : variable qui est annoncée dans la portée globale peut être utilisé n'importe où dans le programme très en douceur. Par exemple:
var carName = " BMW"; // code here can use carName function myFunction() { // code here can use carName }
-
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 }
Global: variable déclarée en dehors d'une fonction
Local: variable déclarée à l'intérieur d'une fonction, et ne peut être appelée que dans ce champ d'application""