La portée est l'un des concepts les plus importants de JavaScript. Si vous souhaitez bien apprendre JavaScript, vous devez comprendre le fonctionnement de la portée et des chaînes de portée de JavaScript. L'article d'aujourd'hui fournit une brève introduction à la portée et à la chaîne de portée de JavaScript, dans l'espoir d'aider tout le monde à mieux apprendre JavaScript.
Portée JavaScript
Tout langage de programmation a le concept de portée. En termes simples, la portée est la gamme accessible de variables et de fonctions. En JavaScript, il existe deux types de portée de variable : la portée globale et la portée locale.
1. Portée mondiale
Les objets accessibles n'importe où dans le code ont une portée globale. De manière générale, les situations suivantes ont une portée globale :
(1) La fonction la plus externe et les variables définies en dehors de la fonction la plus externe ont une portée globale, par exemple :
Copiez le code comme suit :
varauthorName="Ruisseau à flanc de montagne";
functiondoSomething(){
varblogName="";
functioninnerSay(){
alert(nom du blog);
}
innerSay();
}
alert(authorName);//Crique à flanc de montagne
alert(blogName);//Erreur de script
faire quelque chose();//
innerSay()//erreur de script
(2) Toutes les variables qui ne sont pas définies et directement affectées sont automatiquement déclarées comme ayant une portée globale, par exemple :
Copiez le code comme suit :
functiondoSomething(){
varauthorName="Ruisseau à flanc de montagne";
nom du blog="";
alerte (nom de l'auteur);
}
alerte(nom du blog);//
alert(authorName);//Erreur de script
La variable blogName a une portée globale, mais authorName n'est pas accessible en dehors de la fonction.
(3) Toutes les propriétés des objets fenêtre ont une portée globale
Généralement, les propriétés intégrées de l'objet window ont une portée globale, telle que window.name, window.location, window.top, etc.
2. Portée locale
Contrairement à la portée globale, la portée locale n'est généralement accessible que dans un morceau de code fixe, le plus souvent dans une fonction. Ainsi, à certains endroits, vous verrez également des gens faire référence à cette portée comme une portée de fonction, comme le code suivant. blogName et la fonction innerSay in ont uniquement une portée locale.
Copiez le code comme suit :
functiondoSomething(){
varblogName="";
functioninnerSay(){
alert(nom du blog);
}
innerSay();
}
alert(blogName);//Erreur de script
innerSay();//erreur de script
Chaîne de portée
En JavaScript, les fonctions sont aussi des objets. En fait, tout en JavaScript est un objet. Les objets fonction, comme les autres objets, possèdent des propriétés accessibles via le code et un ensemble de propriétés internes accessibles uniquement au moteur JavaScript. L'une des propriétés internes est [[Scope]], définie par la troisième édition de la norme ECMA-262. Cette propriété interne contient la collection d'objets dans la portée dans laquelle la fonction est créée. Cette collection est appelée la chaîne de portée de la fonction. , qui détermine quelles données sont accessibles par la fonction.
Lorsqu'une fonction est créée, sa chaîne de portée est remplie d'objets de données accessibles depuis la portée dans laquelle la fonction a été créée. Par exemple, définissez la fonction suivante :
Copiez le code comme suit :
fonctionajouter(num1,num2){
varsum=num1+num2;
somme de retour ;
}
Lorsque la fonction add est créée, sa chaîne de portée sera remplie avec un objet global, qui contient toutes les variables globales, comme le montre la figure suivante (remarque : l'image n'illustre qu'une partie de toutes les variables) :
La portée de la fonction add sera utilisée lors de l'exécution. Par exemple, exécutez le code suivant :
Copiez le code comme suit :
var total = ajouter (5,10);
Lorsque cette fonction est exécutée, un objet interne appelé « contexte d'exécution » est créé. Le contexte d'exécution définit l'environnement dans lequel la fonction est exécutée. Chaque contexte d'exécution possède sa propre chaîne de portée pour la résolution des identifiants. Lorsqu'un contexte d'exécution est créé, sa chaîne de portée est initialisée avec l'objet contenu dans [[Scope]] de la fonction en cours d'exécution.
Les valeurs sont copiées dans la chaîne de portée du contexte d'exécution dans l'ordre dans lequel elles apparaissent dans la fonction. Ensemble, ils forment un nouvel objet appelé "objet d'activation". Cet objet contient toutes les variables locales, les paramètres nommés, les collections de paramètres et ceux de la fonction. Cet objet sera ensuite poussé vers l'avant de la chaîne de portée. est détruit, l'objet actif est également détruit. La nouvelle chaîne de portées est présentée ci-dessous :
Lors de l'exécution de la fonction, si une variable n'est pas rencontrée, elle passera par un processus de résolution d'identifiant pour déterminer où obtenir et stocker les données. Ce processus part de la tête de la chaîne de portée, c'est-à-dire de l'objet actif, et recherche un identifiant du même nom. S'il est trouvé, utilisez la variable correspondant à cet identifiant. S'il n'est pas trouvé, continuez. recherchez l'objet suivant dans la chaîne de portée. Si aucun objet n'est trouvé après la recherche, l'identifiant est considéré comme indéfini. Lors de l'exécution de la fonction, chaque identifiant subit un tel processus de recherche.
Chaînage de portée et optimisation du code
Il ressort de la structure de la chaîne de portées que plus l'identifiant est situé profondément dans la chaîne de portées du contexte d'exécution, plus la vitesse de lecture et d'écriture sera lente. Comme le montre la figure ci-dessus, étant donné que les variables globales existent toujours à la fin de la chaîne de portée du contexte d'exécution, la recherche des variables globales est la plus lente lors de la résolution de l'identifiant. Par conséquent, lors de l’écriture de code, vous devez utiliser le moins possible les variables globales et utiliser autant que possible les variables locales. Une bonne règle générale est la suivante : si un objet multi-portée est référencé plus d'une fois, stockez-le dans une variable locale avant de l'utiliser. Par exemple le code suivant :
Copiez le code comme suit :
functionchangeColor(){
document.getElementById("btnChange").onclick=function(){
document.getElementById("targetCanvas").style.backgroundColor="red";
} ;
}
Cette fonction fait référence au document de variable globale deux fois. Pour trouver la variable, vous devez parcourir toute la chaîne de portée jusqu'à ce qu'elle soit finalement trouvée dans l'objet global. Ce code peut être réécrit comme suit :
Copiez le code comme suit :
functionchangeColor(){
vardoc=document;
doc.getElementById("btnChange").onclick=function(){
doc.getElementById("targetCanvas").style.backgroundColor="red";
} ;
}
Ce code est relativement simple et ne montrera pas une énorme amélioration des performances après la réécriture. Cependant, s'il y a un grand nombre de variables globales dans le programme qui sont consultées à plusieurs reprises, les performances du code réécrit seront considérablement améliorées.
modifier la chaîne de portée
Le contexte d'exécution correspondant est unique à chaque fois qu'une fonction est exécutée, donc appeler la même fonction plusieurs fois entraînera la création de plusieurs contextes d'exécution. Lorsque la fonction termine son exécution, le contexte d'exécution sera détruit. Chaque contexte d'exécution est associé à une chaîne de portées. Dans des circonstances normales, lors de l'exécution du contexte d'exécution, sa chaîne de portées ne sera affectée que par l'instruction with et l'instruction catch.
L'instruction with est un raccourci pour utiliser des objets afin d'éviter d'écrire du code répété. Par exemple:
Copiez le code comme suit :
fonctioninitUI(){
avec(document){
varbd=corps,
liens=getElementsByTagName("a"),
je = 0,
len=liens.longueur;
pendant que(i<len){
update(liens[i++]);
}
getElementById("btnInit").onclick=function(){
faire quelque chose();
} ;
}
}
L'instruction width est utilisée ici pour éviter d'écrire le document plusieurs fois, ce qui semble plus efficace, mais entraîne en réalité des problèmes de performances.
Lorsque le code atteint l'instruction with, la chaîne de portée du contexte d'exécution est temporairement modifiée. Un nouvel objet mutable est créé et contient toutes les propriétés de l'objet spécifié par le paramètre. Cet objet sera poussé en tête de la chaîne de portée, ce qui signifie que toutes les variables locales de la fonction sont désormais dans le deuxième objet de la chaîne de portée, et donc plus coûteuses d'accès. Comme indiqué ci-dessous :
Par conséquent, vous devez éviter d'utiliser l'instruction with dans votre programme. Dans cet exemple, le simple fait de stocker le document dans une variable locale peut améliorer les performances.
Une autre chose qui modifie la chaîne de portée est l'instruction catch dans l'instruction try-catch. Lorsqu'une erreur se produit dans le bloc de code try, le processus d'exécution passe à l'instruction catch, puis l'objet d'exception est poussé dans un objet mutable et placé en tête de la portée. À l'intérieur du bloc catch, toutes les variables locales de la fonction seront placées dans le deuxième objet de chaîne de portée. Exemple de code :
Copiez le code comme suit :
essayer{
faire quelque chose();
}attraper(ex){
alert(ex.message);//La chaîne de portée change ici
}
Veuillez noter qu'une fois l'instruction catch exécutée, la chaîne de portée reviendra à son état précédent. L'instruction try-catch est très utile pour le débogage du code et la gestion des exceptions, il n'est donc pas recommandé de l'éviter complètement. Vous pouvez réduire l'impact des instructions catch sur les performances en optimisant votre code. Un bon modèle consiste à déléguer la gestion des erreurs à une fonction, par exemple :
Copiez le code comme suit :
essayer{
faire quelque chose();
}attraper(ex){
handleError(ex);//Déléguer à la méthode du processeur
}
Dans le code optimisé, la méthode handleError est le seul code exécuté dans la clause catch. Cette fonction reçoit un objet d'exception en tant que paramètre, afin que vous puissiez gérer les erreurs de manière plus flexible et uniforme. Étant donné qu'une seule instruction est exécutée et qu'aucune variable locale n'est accessible, les modifications temporaires dans la chaîne de portée n'affecteront pas les performances du code.