(1) Portée
La portée d'une variable est la zone de la variable définie dans le code source du programme.
1. La portée lexicale est utilisée en JS
Les variables qui ne sont déclarées dans aucune fonction (var est omise dans une fonction sont également considérées comme globales) sont appelées variables globales (portée globale)
Les variables déclarées dans une fonction ont une portée de fonction et sont des variables locales
Les variables locales ont une priorité plus élevée que les variables globales
Omettre var dans la fonction affectera la variable globale, car elle a en fait été réécrite en variable globale
Portée de la fonction, c'est-à-dire que la fonction est l'unité de base d'une portée js n'a pas de portée au niveau du bloc comme c/c, comme if for, etc.
Bien sûr, des fonctions d'ordre supérieur sont également utilisées dans js, qui peuvent en fait être comprises comme des fonctions imbriquées
Après test1(), la fonction externe sera appelée et une fonction interne sera renvoyée. Ensuite, continue(), et la fonction interne sera appelée et exécutée en conséquence, donc "one"
sera affiché.Les fonctions imbriquées impliquent des fermetures, dont nous parlerons plus tard. Ici, la fonction interne peut accéder au nom de variable déclaré dans la fonction externe, ce qui implique le mécanisme de chaîne de portée
2. Déclaration en JS à l'avance
La portée de la fonction en js signifie que toutes les variables déclarées dans la fonction sont toujours visibles dans le corps de la fonction. De plus, la variable peut être utilisée avant d'être déclarée. Cette situation est appelée levage
.astuce : La déclaration à l'avance est effectuée lorsque le moteur js est pré-compilé. Le phénomène de déclaration à l'avance se produit avant l'exécution du code
.Par exemple
Ce qui précède produit l'effet suivant
Essayez à nouveau de supprimer var ? C'est le nom au sein de la fonction qui est devenue une variable globale, elle n'est donc plus indéfinie
3. Il convient de noter qu'aucun des paramètres mentionnés ci-dessus n'est réussi. Que se passe-t-il si le test a des paramètres ?
Comme mentionné précédemment, les types de base sont transmis par valeur, donc le nom transmis au test n'est en fait qu'une copie. Cette copie est effacée après le retour de la fonction.
Ne pensez pas que name="two" dans la fonction change le nom global, car ce sont deux noms indépendants
(2) Chaîne de portée
Les fonctions avancées mentionnées ci-dessus impliquent une chaîne de portée
1. Présentez un grand paragraphe pour expliquer :
Chaque élément de code JavaScript (code global ou fonction) est associé à une chaîne de portées.
Cette chaîne de portée est une liste ou une liste chaînée d'objets. Ce groupe d'objets définit les variables "dans la portée" dans ce code.
Lorsque js a besoin de trouver la valeur de la variable x (ce processus est appelé résolution de variable), il commencera à partir du premier objet de la chaîne. Si cet objet a un attribut nommé x, alors la valeur de cet attribut sera. utilisé directement. S'il n'y a pas d'attribut nommé x dans le premier objet, js continuera à rechercher l'objet suivant dans la chaîne. Si le deuxième objet n’a toujours pas d’attribut nommé x, il continuera à chercher le suivant, et ainsi de suite. Si aucun objet dans la chaîne de portée ne contient l'attribut x, alors on considère que x n'existe pas dans la chaîne de portée de ce code, et finalement une exception ReferenceError est levée.
2. Exemple de chaîne de portée :
Dans le code de niveau supérieur de js (c'est-à-dire le code qui n'inclut aucune définition de fonction), la chaîne de portée est constituée d'un objet global.
Dans un corps de fonction qui ne contient pas d'imbrication, il y a deux objets sur la chaîne de portée. Le premier est l'objet qui définit les paramètres de la fonction et les variables locales, et le second est l'objet global.
Dans un corps de fonction imbriqué, il y a au moins trois objets dans la portée.
3. Règles de création de chaîne de portée :
Lorsqu'une fonction est définie (notez qu'elle démarre lorsqu'elle est définie), elle enregistre en fait une chaîne de portées.
Lorsque cette fonction est appelée, elle crée un nouvel objet pour stocker ses paramètres ou variables locales, ajoute l'objet à cette chaîne de portée et crée une nouvelle représentation plus longue de la portée appelant la fonction.
Pour les fonctions imbriquées, la situation change à nouveau : à chaque fois que la fonction externe est appelée, la fonction interne sera à nouveau redéfinie. Car chaque fois qu’une fonction externe est appelée, la chaîne de portées est différente. Les fonctions internes doivent être subtilement différentes à chaque fois qu'elles sont définies - le code de la fonction interne est le même à chaque fois que la fonction externe est appelée, et la chaîne de portée associée à ce code est également différente.
(astuce : Comprenez bien les trois points ci-dessus et souvenez-vous-en. Il est préférable de le dire avec vos propres mots, sinon vous devrez le mémoriser, car l'intervieweur vous demandera directement : Veuillez décrire la chaîne de portée.. . )
Un exemple pratique de chaînage de portée :
Ce qui précède est une fonction imbriquée, il devrait donc y avoir trois objets dans la chaîne de portée
Ensuite, lors de l'appel, vous devez trouver la valeur du nom, recherchez simplement
Lorsque test1() est appelé avec succès, l'ordre est test1()->test()-> Parce que la valeur trois de name est trouvée sur test1(), la recherche est terminée et renvoie <.> Lorsque test1() est appelé avec succès, l'ordre est test2()->test()->fenêtre d'objet globale Parce que la valeur de name n'est pas trouvée sur test2(), nous la recherchons dans test(. ) et trouvez-le Si la valeur de name est deux, la recherche sera terminée et renverra
.
Un autre exemple est que parfois nous faisons des erreurs et sommes souvent trompés lors des entretiens.
為什麼?
根據作用域鏈中指標的查找規則:
這裡有一個函數,它是匿名函數,既然是函數,那麼在域鏈上有一個作用對象,這個函數裡邊使用到了變數i,它自然會在作用域上找到它。
查找順序是這個匿名函數 --> 外部的函數buttonInit() --> 全域物件window
匿名函數中找不到i,自然找到了buttonInit(),ok,在for中找到了,
今年註冊事件已經結束了,以為它會一個把我放下來,因為函數作用域內的變數對作用域內是一直可見的,也就是說會保持到最後的狀態
當匿名函數要使用i的時候,註冊事件完了,i已經變成了4,所以都是Button4
那要怎麼解決呢?
給它傳值進去吧,每次循環時,再使用一個匿名函數,把裡邊的i傳進去,匿名函數的規則如程式碼
這樣就可以Button1..2..3了
4.上述就是作用域鏈的基本描述,另外,with語句可用於臨時拓展作用域鏈(不建議使用with)
語法形如:
與(對象)
聲明
這個with語句,將物件加入到作用域鏈的頭部,然後執行語句,最後把作用域鏈恢復到原始狀態
簡單用法:
例如給表單中各項目的值賦值
一般我們可以這樣直接
引入with後(因為使用with會產生一系列問題,所以還是使用上面那張形式吧)
另外,假如 一個物件o具有x屬性,o.x = 1;
那麼使用
就可以轉換成 o.x = 2;
假如o沒有定義屬性x,它的功能就只是相當於 x = 2; 一個全域變數罷了。
因為with提供了一種讀取o的屬性的快捷方式,但他並不能創建o本身沒有的屬性。
以上所述就是本文的全部內容了,希望能夠對大家學習javascript有所幫助。