ホームページ > 記事 > ウェブフロントエンド > JSの実行コンテキストと実行スタックの詳細説明
JavaScript 開発者、または JavaScript 開発者になりたい場合は、JavaScript プログラムの内部実行メカニズムを理解する必要があります。実行コンテキストと実行スタックは、JavaScript の重要な概念の 1 つであり、JavaScript の難しさの 1 つです。実行コンテキストと実行スタックを理解することは、ホイスティング メカニズム、スコープ、クロージャなどの他の JavaScript の概念を理解するのにも役立ちます。この記事では、これらの概念をできるだけわかりやすく紹介します。
推奨チュートリアル: 「JavaScript ビデオ チュートリアル 」
要するに、実行コンテキストは、現在の JavaScript コードが解析および実行される環境の抽象的な概念です。JavaScript で実行されるコードはすべて、実行コンテキストで実行されます。
実行コンテキストには 3 つのタイプがあります:
実行コンテキストのライフ サイクルには 3 つの段階があります: 作成段階→実行段階→リサイクル段階、この記事創造段階に焦点を当てます。
関数が呼び出されるとき、その内部コードが実行される前に、次の 3 つのことが行われます:
JS スクリプトを実行する前に、コードを解析する必要があります (つまり、JS はスクリプト言語です)解釈して実行する) を解析するときに、グローバル実行コンテキストが最初に作成され、実行されるコード内のすべての変数と関数の宣言が最初に取り出されます。変数は一時的に未定義に割り当てられ、関数は宣言されて使用できるようになります。このステップが完了すると、正式な実行プロセスを開始できます。
さらに、関数が実行される前に、関数実行コンテキストも作成されます。これはグローバル コンテキストに似ていますが、関数実行コンテキストにはこの引数と関数パラメーターが含まれます。
実行変数の割り当て、コードの実行
実行コンテキストはスタックからポップされ、実行コンテキストをリサイクルするための仮想マシン
console.log(a); // undefined var a = 10;
上記のコードは、通常、エラー
Uncaught ReferenceError: a が定義されていません## を報告する代わりに、unknown を出力します。 #、これはステートメントの巻き上げが原因であり、次のコードと同等です:
var a; //声明 默认值是undefined “准备工作” console.log(a); a = 10; //赋值
2. 関数宣言のプロモーション
関数を作成するには 2 つの方法があることは誰もが知っています。関数宣言を通して もう 1 つは関数式を通してです var foo = function(){}
では、関数の昇格における 2 つの違いは何ですか? ?
console.log(f1); // function f1(){} function f1() {} // 函数声明 console.log(f2); // undefined var f2 = function() {}; // 函数表达式
次に例を使用してこの問題を説明します。
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();上の例では、foo() が呼び出されたときにエラーが報告されますが、bar は通常どおり呼び出すことができます。 変数と関数が上昇すると前に述べましたが、関数式
var foo = function(){}
に遭遇すると、var foo は最初に At the まで上昇します。ただし、この時点の foo の値は未定義であるため、
foo() を実行するとエラーが報告されます。
而对于函数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();
上述代码运行按照如下步骤:
更多编程相关知识,请访问:编程学习网站!!
以上がJSの実行コンテキストと実行スタックの詳細説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。