En JavaScript, scope correspond au contexte dans lequel le code est exécuté. Il existe trois types de portée: portée globale, portée locale (parfois appelée "portée de la fonction") et portée eval..
Code défini à l'aide de var
L’intérieur d’une fonction est délimité localement et n’est "visible" que par les autres expressions de cette fonction, ce qui inclut le code à l’intérieur de toute fonction imbriquée / enfant. Les variables définies dans l'étendue globale sont accessibles de n'importe où car il s'agit du niveau le plus élevé et du dernier arrêt de la chaîne d'étendue..
Examinez le code qui suit et assurez-vous de bien comprendre que chaque déclaration de foo
est unique en raison de sa portée.
Échantillon: sample110.html
Assurez-vous de comprendre que chaque foo
La variable contient une valeur différente, car chacune d’elles est définie dans une portée spécifiquement définie..
Vous pouvez créer un nombre illimité d’étendues de fonctions et d’évaluations, alors qu’un seul environnement global est utilisé par un environnement JavaScript..
La portée globale est la dernière étape de la chaîne de la portée.
Les fonctions contenant des fonctions créent des étendues d'exécution empilées. Ces piles, qui sont enchaînées, sont souvent appelées la chaîne de la portée..
Depuis les déclarations logiques (si
) et des instructions en boucle (pour
) ne créez pas de portée, les variables peuvent s’écraser. Examinez le code suivant et assurez-vous de bien comprendre que la valeur de foo
est redéfini alors que le programme exécute le code.
Échantillon: sample111.html
Alors foo
est en train de changer au fur et à mesure de l'exécution du code car JavaScript n'a pas de portée d'étendue de bloc, ni globale, ni d'évaluation.
var
À l'intérieur des fonctions permettant de déclarer des variables et d'éviter les pièges liés à l'étendueJavaScript déclarera toutes les variables dépourvues de var
déclaration (même celles contenues dans une fonction ou des fonctions encapsulées) d'être dans la portée globale au lieu de la portée locale prévue. Regardez le code qui suit et remarquez que sans l'utilisation de var
pour déclarer bar, la variable est définie dans la portée globale et non dans la portée locale, où elle devrait être.
Échantillon: sample112.html
Le concept à retenir ici est que vous devriez toujours utiliser var
lors de la définition de variables à l'intérieur d'une fonction. Cela vous évitera de traiter avec des problèmes de portée potentiellement déroutants. L'exception à cette convention, bien sûr, est lorsque vous souhaitez créer ou modifier des propriétés dans la portée globale à partir d'une fonction.
Une chaîne de recherche est suivie lorsque JavaScript recherche la valeur associée à une variable. Cette chaîne est basée sur la hiérarchie de la portée. Dans le code qui suit, je consigne la valeur de sayHiText
du func2
portée de la fonction.
Échantillon: sample113.html
Comment est la valeur de sayHiText
trouvé quand il n'est pas contenu dans le champ d'application du func2
une fonction? JavaScript commence par apparaître dans le func2
fonction pour une variable nommée sayHiText
. Ne pas trouver func2
là-bas, il semble func2
s fonction parent, func1
. le sayHiText
variable ne se trouve pas dans le func1
portée, soit, donc JavaScript continue ensuite jusqu'à la portée globale où sayHiText
est trouvé, à quel point la valeur de sayHiText
est livré. Si sayHiText
n'avait pas été défini dans la portée globale, indéfini
aurait été retourné par JavaScript.
C'est un concept très important à comprendre. Examinons un autre exemple de code, dans lequel nous prenons trois valeurs de trois portées différentes..
Échantillon: sample114.html
La valeur pour z
est local à la bar
fonction et le contexte dans lequel le console.log
est invoqué. La valeur pour y
est dans le foo
fonction, qui est le parent de bar()
, et la valeur pour X
est dans la portée globale. Tous ces éléments sont accessibles au bar
fonction via la chaîne de l'oscilloscope. Assurez-vous de comprendre que le référencement des variables dans le bar
la fonction vérifiera tout au long de la chaîne de la portée pour les variables référencées.
La chaîne de la portée, si vous y réfléchissez, n'est pas si différente de la chaîne des prototypes. Les deux sont simplement un moyen de rechercher une valeur en vérifiant un ensemble d'emplacements systématique et hiérarchique..
Dans l’exemple de code qui suit, une variable appelée X
existe dans le même champ dans lequel il est examiné avec console.log
. Cette valeur "locale" de X
est utilisé, et on pourrait dire qu'il ombres, ou masques, le même nom X
les variables trouvées plus haut dans la chaîne de la portée.
Échantillon: sample115.html
N'oubliez pas que la recherche de portée se termine lorsque la variable est trouvée dans le lien disponible le plus proche de la chaîne, même si le même nom de variable est utilisé plus haut dans la chaîne..
Comme les fonctions déterminent la portée et que les fonctions peuvent être transmises comme n'importe quelle valeur JavaScript, on pourrait penser que déchiffrer la chaîne de la portée est compliqué. C'est en fait très simple. La chaîne d'étendue est décidée en fonction de l'emplacement d'une fonction lors de la définition, pas lors de l'appel. Cela s'appelle également la portée lexicale. Réfléchissez longuement à cela, car la plupart des gens trébuchent souvent dessus en code JavaScript..
La chaîne d'étendue est créée avant que vous appeliez une fonction. De ce fait, nous pouvons créer des fermetures. Par exemple, une fonction peut renvoyer une fonction imbriquée à l'étendue globale, mais notre fonction peut toujours accéder, via la chaîne d'étendue, à l'étendue de sa fonction parente. Dans l'exemple suivant, nous définissons un parentFunction
qui retourne une fonction anonyme, et nous appelons la fonction retournée à partir de la portée globale. Parce que notre fonction anonyme a été définie comme étant contenue à l'intérieur de parentFunction
, il a toujours accès à fonctions parentales
portée quand il est invoqué. Ceci s'appelle une fermeture.
Échantillon: sample116.html
L'idée que vous devriez retenir ici est que la chaîne d'étendue est déterminée lors de la définition, littéralement dans la manière dont le code est écrit. Passer des fonctions à l'intérieur de votre code ne changera pas la chaîne de l'oscilloscope.
Prenez ce que vous avez appris sur la chaîne et la recherche de portée de cet article, et une fermeture ne devrait pas être trop compliquée à comprendre. Dans l'exemple suivant, nous créons une fonction appelée countUpFromZero
. Cette fonction renvoie en fait une référence à la fonction enfant qu’elle contient. Lorsque cette fonction enfant (fonction imbriquée) est appelée, elle a toujours accès à la portée de la fonction parent en raison de la chaîne de portée..
Échantillon: sample117.html
A chaque fois le countUpFromZero
fonction est appelée, la fonction anonyme contenue dans (et renvoyée de) la countUpFromZero
fonction a toujours accès à la portée de la fonction parent. Cette technique, facilitée via la chaîne du scope, est un exemple de fermeture.
Si vous croyez que j'ai des fermetures trop simplistes, vous avez probablement raison dans cette idée. Mais je l’ai fait à dessein, car j'estime que les parties importantes proviennent d’une solide compréhension des fonctions et de la portée, pas nécessairement de la complexité du contexte d’exécution. Si vous avez besoin d'une plongée en profondeur dans les fermetures, consultez JavaScript Closures.