Dieses Mal werde ich Ihnen eine Analyse der zugrunde liegenden Funktionen des Javascript-Bereichs und der Vorsichtsmaßnahmen für die Verwendung des zugrunde liegenden Javascript-Bereichs geben Fall, werfen wir einen Blick darauf.
Tag: Javascript
-Bereich wird im Programmquellcode generiert, wobei die Variable definiert, und wird während der Programmcodierungsphase bestimmt. JavaScript ist in einen globalen Bereich (Globaler Kontext: window
/global
) und einen lokalen Bereich (Lokaler Bereich, auch bekannt als Funktionsbereich Funktionskontext) unterteilt. Einfach ausgedrückt ist der Bereich der 生成环境
oder 上下文
der aktuellen Funktion (Hinweis: Verwechseln Sie ihn nicht mit dem später erwähnten 执行上下文
), einschließlich der in der aktuellen Funktion definierten Variablen und der -Referenz auf der äußere Geltungsbereich.
Bereich in Javascript:
作用域(Scope) | - |
---|---|
window/global Scope | 全局作用域 |
function Scope | 函数作用域 |
Block Scope | 块作用域(ES6) |
eval Scope | eval作用域 |
Scope definiert eine Reihe von Regeln, die definieren, wie die Engine Variablen basierend auf Bezeichnern im aktuellen Bereich und in verschachtelten Bereichen abfragt. Andererseits bestimmt die aus N Bereichen bestehende Bereichskette den Wert, den der Bezeichner innerhalb des Funktionsbereichs findet.
Wir können es also wie folgt zusammenfassen: Der Bereich bestimmt die Sichtbarkeit der im aktuellen Kontext definierten Variablen, d. h. auf den untergeordneten Bereich kann zugegriffen werden. Und die Bereichskette (Scope Chain) bestimmt auch, wie der Wert des Bezeichners im aktuellen Kontext ermittelt wird.
Der Geltungsbereich ist in lexikalischen Geltungsbereich und dynamischen Geltungsbereich unterteilt. Der lexikalische Geltungsbereich ist im wahrsten Sinne des Wortes der in der lexikalischen Phase definierte Geltungsbereich. Mit anderen Worten: Der Bereich wird festgelegt, wenn der Lexer den Quellcode verarbeitet, basierend auf der Position von Variablen und Blöcken im Quellcode. JavaScript verwendet den lexikalischen Bereich.
Zugriffsregeln für Variablen:
Wenn Variable a innerhalb einer Funktion definiert ist, haben andere Variablen innerhalb der Funktion die Berechtigung, auf Variable a zuzugreifen, Code außerhalb der Funktion jedoch schon keinen Zugriff auf die Variablenberechtigungen von a haben. Daher können Variablen im selben Bereich aufeinander zugreifen, d. h. a, b und c können aufeinander zugreifen, wenn sie sich im selben Bereich befinden. Es ist, als ob eine Hühnermutter ein Baby hätte, aber die anderen Hühner könnten nicht mit ihnen spielen. Weil Mutter Huhn es nicht zulässt.
let a = 1 function foo () { let b = 1 + a let c = 2 console.log(b) // 2 } console.log(c) // error 全局作用无法访问到 c foo()
Wenn die Variable a im globalen Bereich (Fenster/Global) definiert ist, dann liegt der Ausführungscode im lokalen Bereich unter dem globalen Bereich oder mit anderen Worten Ausdruck kann auf den Wert der Variablen a zugreifen. Eine Variable mit demselben Namen (a) in einer lokalen Variablen schneidet den Zugriff auf die globale Variable a ab. (Die Variable a entspricht hier dem Züchter, und der Züchter füttert die Hühner zum richtigen Zeitpunkt. Um jedoch Kosten zu sparen, schreibt der Landwirt vor, dass der Züchter die Hühner in der Nähe füttern muss. Wenn der Züchter 1 die Hühner verlässt , In jüngerer Zeit werden andere Züchter nicht mehr in der Lage sein, den ganzen Weg über den Yalu-Fluss zu reisen, um Hühner zu füttern)
let a = 1 let b = 2 function foo () { let b = 3 function too () { console.log(a) // 1 console.log(b) // 3 } too() } foo()
Auch hier wird der JavaScript-Bereich den zugänglichen Bereich von Variablen strikt einschränken: Das heißt, basierend auf dem Quellcode hat der verschachtelte Bereich Zugriff auf den verschachtelten Bereich. (Diese Regel zeigt, dass die gesamte Farm Regeln hat und nicht in die entgegengesetzte Richtung füttern kann.)
Die Bereichskette besteht aus der aktuellen Umgebung und der oberen Ebene Die Umgebung besteht aus einer Reihe von Bereichen, die sicherstellen, dass die aktuelle Ausführungsumgebung ordnungsgemäßen Zugriff auf Variablen und Funktionen hat, die den Zugriffsberechtigungen entsprechen.
Die obige Erklärung ist etwas unklar. Für jemanden wie mich, der ein schwaches Gehirn hat, muss ich sie mehrmals in meinem Gehirn „lesen“, um sie zu verstehen. Wozu dient die Scope-Kette? Einfach ausgedrückt analysiert die Bereichskette den Bezeichner und ist dafür verantwortlich, den Wert der Variablen zurückzugeben, von der der Ausdruck abhängt, wenn er ausgeführt wird. Eine einfachere Antwort: Die Bereichskette wird zum Suchen von Variablen verwendet. Die Bereichskette besteht aus einer Reihe von Bereichen, die in Reihe geschaltet sind.
Während der Funktionsausführung durchläuft diese jedes Mal, wenn eine Variable angetroffen wird, einen Bezeichnerauflösungsprozess, um zu entscheiden, wo die Daten abgerufen und gespeichert werden sollen. Dieser Prozess beginnt am Kopf der Bereichskette, dem Bereich der aktuell ausgeführten Funktion (von links nach rechts in der Abbildung unten), und sucht nach einem Bezeichner mit demselben Namen. Wenn er gefunden wird, wird der Wert angezeigt, der dem Bezeichner entspricht wird zurückgegeben. Wenn nicht, fahren Sie fort. Der nächste Bereich in der Bereichskette wird durchsucht. Wenn kein Bereich gefunden wird, gilt der Bezeichner als undefiniert. Während der Funktionsausführung muss jeder zu analysierende Bezeichner diesen Suchprozess durchlaufen.
Um das Problem konkret zu analysieren, können wir davon ausgehen, dass die Bereichskette ein Array (Scope Array) ist und die Array-Mitglieder aus einer Reihe variabler Objekte bestehen . Wir können den Einwegkanal des Arrays verwenden, das heißt, die obige Abbildung simuliert die Abfrage der Bezeichner im Variablenobjekt von links nach rechts, sodass wir auf die Variablen im oberen Bereich zugreifen können. bis zur obersten Ebene (globaler Bereich), und sobald sie gefunden wurde, stoppt die Suche. Daher kann die innere Variable die äußere Variable mit demselben Namen abschirmen. Denken Sie darüber nach, wenn Variablen nicht von innen nach außen durchsucht werden, wird das gesamte Sprachdesign N komplizierter (wir müssen ein komplexes Regelwerk für Hühnerbabys entwerfen, um Futter zu finden)
Immer noch mit der Kastanie oben:
let a = 1 let b = 2 function foo () { let b = 3 function too () { console.log(a) // 1 console.log(b) // 3 } too() } foo()
Die verschachtelte Bereichsstruktur sieht folgendermaßen aus:
栗子中,当 javascript 引擎执行到函数 too 时, 全局、函数 foo、函数 too 的上下文分别会被创建。上下文内包含它们各自的变量对象和作用域链(注意: 作用域链包含可访问到的上层作用域的变量对象,在上下文创建阶段根据作用域规则被收集起来形成一个可访问链),我们设定他们的变量对象分别为VO(global),VO(foo), VO(too)。而 too 的作用域链,则同时包含了这三个变量对象,所以 too 的执行上下文可如下表示:
too = { VO: {...}, // 变量对象 scopeChain: [VO(too), VO(foo), VO(global)], // 作用域链 }
我们可以直接用scopeChain
来表示作用域链数组,数组的第一项scopeChain[0]为作用域链的最前端(当前函数的变量对象),而数组的最后一项,为作用域链的最末端(全局变量对象 window )。所有作用域链的最末端都为全局变量对象。
再举个栗子:
let a = 1 function foo() { console.log(a) } function too() { let a = 2 foo() } too() // 1
这个栗子如果对作用域的特点理解不透彻很容易以为输出是2。但其实最终输出的是 1。 foo() 在执行的时候先在当前作用域内查找变量 a 。然后根据函数定义时的作用域关系会在当前作用域的上层作用域里查找变量标识符 a,所以最后查到的是全局作用域的 a 而不是 foo函数里面的 a 。
变量对象、执行上下文会在后面介绍。
在 JavaScript 中,函数和函数声明时的词法作用域形成闭包。我们来看个闭包的例子
let a = 1 function foo() { let a = 2 function too() { console.log(a) } return too } foo()() // 2
这是一个闭包的栗子,一个函数执行后返回另一个可执行函数,被返回的函数保留有对它定义时外层函数作用域的访问权。foo()()
调用时依次执行了 foo、too 函数。too 虽然是在全局作用域里执行的,但是too定义在 foo 作用域里面,根据作用域链规则取最近的嵌套作用域的属性 a = 2。
再拿农场的故事做比如。农场主发现还有一种方法会更节约成本,就是让每个鸡妈妈作为家庭成员的‘饲养员’, 从而改变了之前的‘饲养结构’。
关于闭包会在后面的章节里也会有介绍。
从作用域链的结构可以发现,javascript
引擎在查找变量标识符时是依据作用域链依次向上查找的。当标识符所在的作用域位于作用域链的更深的位置,读写的时候相对就慢一些。所以在编写代码的时候应尽量少使用全局代码,尽可能的将全局的变量缓存在局部作用域中。
不加强记忆很容记错作用域与后面将要介绍的执行上下文的区别。代码的执行过程分为编译阶段和解释执行阶段。始终应该记住javascript
作用域在源代码的编码阶段就确定了,而作用域链是在编译阶段被收集到执行上下文的变量对象里的。所以作用域、作用域链都是在当前运行环境内代码执行前就确定了。这里暂且不过多的展开执行上下文的概念,可以关注后续文章。
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
EasyCanvas绘图库在Pixeler项目开发中使用实战总结
Das obige ist der detaillierte Inhalt vonAnalyse der zugrunde liegenden Funktionen des Javascript-Bereichs. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!