Wenn Sie JavaScript-Entwickler sind oder JavaScript-Entwickler werden möchten, müssen Sie den internen Ausführungsmechanismus eines JavaScript-Programms kennen. Ausführungskontext und Ausführungsstapel sind eines der Schlüsselkonzepte in JavaScript und eine der Schwierigkeiten in JavaScript. Das Verständnis des Ausführungskontexts und des Ausführungsstapels hilft auch, andere JavaScript-Konzepte wie Hebemechanismus, Umfang und Abschluss zu verstehen. In diesem Artikel werden diese Konzepte so leicht verständlich wie möglich vorgestellt.
Empfohlenes Tutorial: „JavaScript-Video-Tutorial“
1. Ausführungskontext1. Kurz gesagt, Ausführungskontext ist die Umgebung, in der der aktuelle JavaScript-Code analysiert und ausgeführt wird. Abstraktes Konzept Code, der in JavaScript ausgeführt wird, wird in einem Ausführungskontext ausgeführt2. Arten von Ausführungskontexten:Funktionsausführungskontext: Bei jedem Aufruf einer Funktion wird ein neuer Ausführungskontext für die Funktion erstellt. Jede Funktion verfügt über einen eigenen Ausführungskontext, der jedoch nur beim Aufruf der Funktion erstellt wird. In einem Programm können beliebig viele Funktionsausführungskontexte vorhanden sein. Immer wenn ein neuer Ausführungskontext erstellt wird, führt er eine Reihe von Schritten in einer bestimmten Reihenfolge aus, die später in diesem Artikel erläutert wird.
Wenn eine Funktion aufgerufen wird, aber bevor ihr interner Code ausgeführt wird, werden die folgenden drei Dinge durchgeführt:
Bereichskette erstellen: Während der Erstellungsphase des Ausführungskontexts wird die Bereichskette nach dem variablen Objekt erstellt. Die Bereichskette selbst enthält variable Objekte. Die Bereichskette wird zum Auflösen von Variablen verwendet. Wenn Sie aufgefordert werden, eine Variable zu analysieren, beginnt JavaScript immer auf der innersten Ebene der Codeverschachtelung. Wenn die Variable auf der innersten Ebene nicht gefunden wird, springt es eine Ebene höher zum übergeordneten Bereich, bis es die Variable findet.
console.log(a); // undefined var a = 10;
undefiniert</code aus > Anstatt einen Fehler zu melden: <code>Uncaught ReferenceError: a ist nicht definiert
, liegt dies am Deklarations-Heben, was dem folgenden Code entspricht: var a; //声明 默认值是undefined “准备工作” console.log(a); a = 10; //赋值
function foo(){}
var foo = function(){}
, Was ist also der Unterschied zwischen diesen beiden Arten der Funktionsförderung? console.log(f1); // function f1(){} function f1() {} // 函数声明 console.log(f2); // undefined var f2 = function() {}; // 函数表达式
Als nächstes verwenden wir ein Beispiel, um dieses Problem zu veranschaulichen:
function test() { foo(); // Uncaught TypeError "foo is not a function" bar(); // "this will run!" var foo = function() { // function expression assigned to local variable 'foo' alert("this won't run!"); }; function bar() { // function declaration, given the name 'bar' alert("this will run!"); } } test();
Im obigen Beispiel wird ein Fehler gemeldet, wenn foo() aufgerufen wird, aber bar kann normal aufgerufen werden. undefined
而不是报错Uncaught ReferenceError: a is not defined
,这是因为声明提升(hoisting),相当于如下代码:
alert(a); //输出:function a(){ alert('我是函数') } function a() { alert("我是函数"); } // var a = "我是变量"; alert(a); //输出:'我是变量'
我们都知道,创建一个函数的方法有两种,一种是通过函数声明function foo(){}
另一种是通过函数表达式var foo = function(){}
,那这两种在函数提升有什么区别呢?
function a() { alert("我是函数"); } var a; //hoisting alert(a); //输出:function a(){ alert('我是函数') } a = "我是变量"; //赋值 alert(a); //输出:'我是变量'
接下来我们通过一个例子来说明这个问题:
function test(arg) { // 1. 形参 arg 是 "hi" // 2. 因为函数声明比变量声明优先级高,所以此时 arg 是 function console.log(arg); var arg = "hello"; // 3.var arg 变量声明被忽略, arg = 'hello'被执行 function arg() { console.log("hello world"); } console.log(arg); } test("hi"); /* 输出: function arg(){ console.log('hello world') } hello */
在上面的例子中,foo()调用的时候报错了,而 bar 能够正常调用。
我们前面说过变量和函数都会上升,遇到函数表达式 var foo = function(){}
时,首先会将var foo
上升到函数体顶部,然而此时的 foo 的值为 undefined,所以执行foo()
var foo = function(){}
stoßen und zuerst zum Funktionskörper At aufsteigen Oben ist jedoch der Wert von foo zu diesem Zeitpunkt undefiniert, sodass bei der Ausführung von foo()
ein Fehler gemeldet wird. 🎜而对于函数bar()
, 则是提升了整个函数,所以bar()
才能够顺利执行。
有个细节必须注意:当遇到函数和变量同名且都会被提升的情况,函数声明优先级比较高,因此变量声明会被函数声明所覆盖,但是可以重新赋值。
alert(a); //输出:function a(){ alert('我是函数') } function a() { alert("我是函数"); } // var a = "我是变量"; alert(a); //输出:'我是变量'
function 声明的优先级比 var 声明高,也就意味着当两个同名变量同时被 function 和 var 声明时,function 声明会覆盖 var 声明
这代码等效于:
function a() { alert("我是函数"); } var a; //hoisting alert(a); //输出:function a(){ alert('我是函数') } a = "我是变量"; //赋值 alert(a); //输出:'我是变量'
最后我们看个复杂点的例子:
function test(arg) { // 1. 形参 arg 是 "hi" // 2. 因为函数声明比变量声明优先级高,所以此时 arg 是 function console.log(arg); var arg = "hello"; // 3.var arg 变量声明被忽略, arg = 'hello'被执行 function arg() { console.log("hello world"); } console.log(arg); } test("hi"); /* 输出: function arg(){ console.log('hello world') } hello */
这是因为当函数执行的时候,首先会形成一个新的私有的作用域,然后依次按照如下的步骤执行:
先搞明白一个很重要的概念 —— this 的值是在执行的时候才能确认,定义的时候不能确认! 为什么呢 —— 因为 this 是执行上下文环境的一部分,而执行上下文需要在代码执行之前确定,而不是定义的时候。看如下例子:
// 情况1 function foo() { console.log(this.a) //1 } var a = 1 foo() // 情况2 function fn(){ console.log(this); } var obj={fn:fn}; obj.fn(); //this->obj // 情况3 function CreateJsPerson(name,age){ //this是当前类的一个实例p1 this.name=name; //=>p1.name=name this.age=age; //=>p1.age=age } var p1=new CreateJsPerson("尹华芝",48); // 情况4 function add(c, d){ return this.a + this.b + c + d; } var o = {a:1, b:3}; add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16 add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34 // 情况5 <button id="btn1">箭头函数this</button> <script type="text/javascript"> let btn1 = document.getElementById('btn1'); let obj = { name: 'kobe', age: 39, getName: function () { btn1.onclick = () => { console.log(this);//obj }; } }; obj.getName(); </script>
接下来我们逐一解释上面几种情况
函数多了,就有多个函数执行上下文,每次调用函数创建一个新的执行上下文,那如何管理创建的那么多执行上下文呢?
JavaScript 引擎创建了执行上下文栈来管理执行上下文。可以把执行上下文栈认为是一个存储函数调用的栈结构,遵循先进后出的原则。
从上面的流程图,我们需要记住几个关键点:
我们再来看个例子:
var color = "blue"; function changeColor() { var anotherColor = "red"; function swapColors() { var tempColor = anotherColor; anotherColor = color; color = tempColor; } swapColors(); } changeColor();
上述代码运行按照如下步骤:
更多编程相关知识,请访问:编程学习网站!!
Das obige ist der detaillierte Inhalt vonDetaillierte Erläuterung des Ausführungskontexts und des Ausführungsstapels in JS. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!