Heim  >  Artikel  >  Web-Frontend  >  Was Sie über Javascript wissen müssen, von der Definition bis zur Ausführung

Was Sie über Javascript wissen müssen, von der Definition bis zur Ausführung

coldplay.xixi
coldplay.xixinach vorne
2020-07-07 16:16:001640Durchsuche

Was Sie über Javascript wissen müssen, von der Definition bis zur Ausführung

Von der Definition bis zur Ausführung von JavaScript leistet die JS-Engine eine Menge Initialisierungsarbeit auf der Implementierungsebene. Bevor wir den Arbeitsmechanismus der JS-Engine erlernen, müssen wir daher mehrere vorstellen Verwandte Konzepte: Ausführungsumgebungsstapel, globale Objekte, Ausführungsumgebungen, variable Objekte, aktive Objekte, Bereiche und Bereichsketten usw. Diese Konzepte sind die Kernkomponenten der JS-Engine. Der Zweck dieses Artikels besteht nicht darin, Ihnen jedes Konzept einzeln zu erklären, sondern anhand einer einfachen Demo eine Analyse durchzuführen und jedes Detail der JS-Engine von der Definition bis zur Ausführung sowie die Rolle, die diese Konzepte darin spielen, umfassend zu erläutern.

Verwandte Lernempfehlungen: Javascript-Video-Tutorial

var x = 1;  //定义一个全局变量 x
function A(y){
   var x = 2;  //定义一个局部变量 x
   function B(z){ //定义一个内部函数 B
       console.log(x+y+z);
   }
   return B; //返回函数B的引用
}
var C = A(1); //执行A,返回B
C(1); //执行函数B

Diese Demo ist ein Abschluss und das Ausführungsergebnis ist 4. Wir werden es unten aufteilen Globale Initialisierung , Funktion A ausführen , Funktion B ausführen drei Stufen zur Analyse des Arbeitsmechanismus der JS-Engine:

1 . Globale Initialisierung

Wenn die JS-Engine einen ausführbaren Code eingibt, muss sie die folgenden drei Initialisierungsaufgaben ausführen:

Erstellen Sie zunächst ein globales Objekt (Global Object). die nur global existiert. Eine Kopie, auf deren Eigenschaften von überall aus zugegriffen werden kann und deren Existenz den gesamten Lebenszyklus der Anwendung begleitet. Wenn das globale Objekt erstellt wird, werden häufig verwendete JS-Objekte wie Math, String, Date und Document als Eigenschaften verwendet.

Da auf dieses globale Objekt nicht direkt über den Namen zugegriffen werden kann, gibt es ein weiteres Attributfenster, und das Fenster zeigt auf sich selbst, sodass über das Fenster auf das globale Objekt zugegriffen werden kann. Die allgemeine Struktur des mit Pseudocode simulierten globalen Objekts ist wie folgt:

//创建一个全局对象
var globalObject = { 
    Math:{},
    String:{},
    Date:{},
    document:{}, //DOM操作
    ...
    window:this //让window属性指向了自身
}

Anschließend muss die JS-Engine einen Ausführungsumgebungsstapel (Ausführungskontextstapel) erstellen eine globale Ausführungsumgebung (Ausführungskontext) EC und schieben Sie diese globale Ausführungsumgebung EC in den Ausführungsumgebungsstapel. Die Funktion des Ausführungsumgebungsstapels besteht darin, sicherzustellen, dass das Programm in der richtigen Reihenfolge ausgeführt werden kann.

In JavaScript verfügt jede Funktion über ihre eigene Ausführungsumgebung. Wenn eine Funktion ausgeführt wird, wird die Ausführungsumgebung der Funktion an die Spitze des Ausführungsumgebungsstapels verschoben und erhält Ausführungsrechte. Wenn die Ausführung der Funktion abgeschlossen ist, wird ihre Ausführungsumgebung von der Oberseite des Stapels entfernt und die Ausführungsrechte werden an die vorherige Ausführungsumgebung zurückgegeben. Wir verwenden Pseudocode, um die Beziehung zwischen dem Ausführungsumgebungsstapel und EC zu simulieren:

var ECStack = []; //定义一个执行环境栈,类似于数组

var EC = {};   //创建一个执行空间,
//ECMA-262规范并没有对EC的数据结构做明确的定义,你可以理解为在内存中分配的一块空间

ECStack.push(EC); //进入函数,压入执行环境
ECStack.pop(EC);  //函数返回后,删除执行环境

Schließlich erstellt die JS-Engine auch ein globales Variablenobjekt (Varibale Object) VO, das EC zugeordnet ist, und verweist VO auf das globale Objekt , VO Es enthält nicht nur die ursprünglichen Attribute des globalen Objekts, sondern auch die global definierte Variable x und die Funktion A. Gleichzeitig wird bei der Definition von Funktion A auch ein interner Attributbereich zu A hinzugefügt, und der Bereich zeigt auf VO. Wenn jede Funktion definiert wird, wird ein ihr zugeordnetes Bereichsattribut erstellt. Der Bereich verweist immer auf die Umgebung, in der die Funktion definiert ist. Die ECStack-Struktur ist zu diesem Zeitpunkt wie folgt:

ECStack = [   //执行环境栈
    EC(G) = {   //全局执行环境
        VO(G):{ //定义全局变量对象
            ... //包含全局对象原有的属性
            x = 1; //定义变量x
            A = function(){...}; //定义函数A
            A[[scope]] = this; //定义A的scope,并赋值为VO本身
        }
    }
];

2. Ausführungsfunktion A

Wenn die Ausführung in A(1) eintritt, muss die JS-Engine Folgendes ausführen Arbeit:

Zuerst erstellt die JS-Engine den Ausführungsumgebungs-EC der Funktion A, und dann wird der EC an die Spitze des Ausführungsumgebungsstapels verschoben und erhält Ausführungsrechte. Derzeit gibt es im Ausführungsumgebungsstapel zwei Ausführungsumgebungen, nämlich die globale Ausführungsumgebung und die Ausführungsumgebung von Funktion A. Die Ausführungsumgebung von A befindet sich oben im Stapel und die globale Ausführungsumgebung unten des Stapels.

Erstellen Sie dann die Bereichskette (Scope Chain) der Funktion A. In JavaScript verfügt jede Ausführungsumgebung über eine eigene Bereichskette für die Bezeichnerauflösung. Wenn die Ausführungsumgebung erstellt wird, wird die Bereichskette auf die initialisiert Objekt, das im Bereich der aktuell ausgeführten Funktion enthalten ist.

Dann erstellt die JS-Engine ein Aktivierungsobjekt (Aktivierungsobjekt) AO der aktuellen Funktion. Das Aktivitätsobjekt spielt hier die Rolle eines variablen Objekts, aber sein Name ist in der Funktion unterschiedlich (Sie können denken). eines variablen Objekts ist ein allgemeines Konzept und das aktive Objekt ist ein Zweig davon), AO enthält die formalen Parameter der Funktion, das Argumentobjekt, dieses Objekt und die Definition lokaler Variablen und interner Funktionen und dann das AO wird in die Oberseite der Zielfernrohrkette geschoben.

Es ist zu beachten, dass die JS-Engine bei der Definition von Funktion B auch ein Bereichsattribut zu B hinzufügt und den Bereich auf die Umgebung verweist, in der Funktion B definiert ist. Die Umgebung, in der Funktion B definiert ist, ist die aktive Umgebung von A Objekt AO, und AO befindet sich am vorderen Ende der verknüpften Liste. Da die verknüpfte Liste Ende an Ende verbunden ist, zeigt der Bereich der Funktion B auf die gesamte Bereichskette von A. Schauen wir uns zu diesem Zeitpunkt die ECStack-Struktur an:

ECStack = [   //执行环境栈
    EC(A) = {   //A的执行环境
        [scope]:VO(G), //VO是全局变量对象
        AO(A) : { //创建函数A的活动对象
            y:1,
            x:2,  //定义局部变量x
            B:function(){...}, //定义函数B
            B[[scope]] = this; //this指代AO本身,而AO位于scopeChain的顶端,因此B[[scope]]指向整个作用域链
            arguments:[],//平时我们在函数中访问的arguments就是AO中的arguments
            this:window  //函数中的this指向调用者window对象
        },
        scopeChain:<AO(A),A[[scope]]>  //链表初始化为A[[scope]],然后再把AO加入该作用域链的顶端,此时A的作用域链:AO(A)->VO(G)
    },
    EC(G) = {   //全局执行环境
        VO(G):{ //创建全局变量对象
            ... //包含全局对象原有的属性
            x = 1; //定义变量x
            A = function(){...}; //定义函数A
            A[[scope]] = this; //定义A的scope,A[[scope]] == VO(G)
        }
    }
];

3. Funktion B ausführen

Nachdem Funktion A ausgeführt wurde, wird ein Verweis auf B zurückgegeben und zugewiesen Für die Variable C entspricht die Ausführung von C(1) der Ausführung von B(1). Die JS-Engine muss die folgende Arbeit ausführen:

Erstellen Sie zunächst wie oben die Ausführungsumgebung EC der Funktion B und dann EC wird in die oberste Ausführungsebene des Umgebungsstapels verschoben und erhält Ausführungsrechte. Derzeit gibt es im Ausführungsumgebungsstapel zwei Ausführungsumgebungen, nämlich die globale Ausführungsumgebung und die Ausführungsumgebung von Funktion B. Die Ausführungsumgebung von B befindet sich oben im Stapel und die globale Ausführungsumgebung unten des Stapels. (Hinweis: Wenn Funktion A zurückkehrt, wird die Ausführungsumgebung von A aus dem Stapel gelöscht, sodass nur die globale Ausführungsumgebung übrig bleibt)

然后,创建函数B的作用域链,并初始化为函数B的scope所包含的对象,即包含了A的作用域链。最后,创 建函数B的活动对象AO,并将B的形参z, arguments对象 和 this对象作为AO的属性。此时ECStack将会变成这样:

ECStack = [   //执行环境栈
    EC(B) = {   //创建B的执行环境,并处于作用域链的顶端
        [scope]:AO(A), //指向函数A的作用域链,AO(A)->VO(G)
        var AO(B) = { //创建函数B的活动对象
            z:1,
            arguments:[],
            this:window
        }
        scopeChain:<AO(B),B[[scope]]>  //链表初始化为B[[scope]],再将AO(B)加入链表表头,此时B的作用域链:AO(B)->AO(A)-VO(G)
    },
    EC(A), //A的执行环境已经从栈顶被删除,
    EC(G) = {   //全局执行环境
        VO:{ //定义全局变量对象
            ... //包含全局对象原有的属性
            x = 1; //定义变量x
            A = function(){...}; //定义函数A
            A[[scope]] = this; //定义A的scope,A[[scope]] == VO(G)
        }
    }
];

当函数B执行“x+y+z”时,需要对x、y、z 三个标识符进行一一解析,解析过程遵守变量查找规则:先查找自己的活动对象中是否存在该属性,如果存在,则停止查找并返回;如果不存在,继续沿着其作用域 链从顶端依次查找,直到找到为止,如果整个作用域链上都未找到该变量,则返回“undefined”。从上面的分析可以看出函数B的作用域链是这样的:

AO(B)->AO(A)->VO(G)

因此,变量x会在AO(A)中被找到,而不会查找VO(G)中的x,变量y也会在AO(A)中被找到,变量z 在自身的AO(B)中就找到了。所以执行结果:2+1+1=4.

简单的总结语

了解了JS引擎的工作机制之后,我们不能只停留在理解概念的层面,而要将其作为基础工具,用以优化和改善我们在实际工作中的代码,提高执行效率,产 生实际价值才是我们的真正目的。就拿变量查找机制来说,如果你的代码嵌套很深,每引用一次全局变量,JS引擎就要查找整个作用域链,比如处于作用域链的最 底端window和document对象就存在这个问题,因此我们围绕这个问题可以做很多性能优化的工作,当然还有其他方面的优化,此处不再赘述,本文仅 当作抛砖引玉吧!

Das obige ist der detaillierte Inhalt vonWas Sie über Javascript wissen müssen, von der Definition bis zur Ausführung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:webhek.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen