首頁  >  文章  >  web前端  >  一文詳解JavaScript中執行上下文與執行堆疊(圖文結合)

一文詳解JavaScript中執行上下文與執行堆疊(圖文結合)

青灯夜游
青灯夜游轉載
2022-10-13 19:23:271964瀏覽

一文詳解JavaScript中執行上下文與執行堆疊(圖文結合)

對我們前端開發者理解JS程式內部執行機制是必要的,其中一個關鍵概念就是Js的執行上下文和執行棧。執行上下文是JS語言較為底層的知識,學習掌握有助於我們更深入的把握JS這門語言的本質,也有助於理解作用域、閉包、變量提升等相關知識。

1 何為執行上下文

程式碼執行前,瀏覽器的Js引擎會先建立程式碼執行的環境來處理此Js程式碼的轉換和執行,程式碼的執行環境稱為執行上下文。

執行上下文是一個抽象概念,包含目前正在運行的程式碼以及幫助其執行的所有內容。

2 分類

執行上下文主要分為三類:

  • 全域執行上下文- 全域程式碼所處的環境,不在函數內部程式碼都在全域執行
  • 函數執行上下文 —— 在函數呼叫時建立的上下文。
  • Eval執行上下文— 運行在Eval函數中程式碼時創建的環境,Eval由於效能問題在我們平時開發中很少用到,所有這裡我們不在討論。

接下來我們將重點放在講全域上下文和函數上下文。

2.1 全域執行上下文

當我們的JS檔案跑起來之後,首先建立的就是全域執行上下文。

當我們的檔案裡沒有一行程式碼時,全域執行上下文中比較乾淨,只有兩個東西。

  • 全域物件(瀏覽器裡是WindowNode在環境下是Global
  • this變數(指向的還是全域物件)

這時候如果我們在檔案裡寫點東西,例如我寫如下程式碼:

var name = '小明'
var age = 18
function showName(){
  return {
      name : name,
      age : age
  }
}

全域執行上下文就會立刻變成這個樣子:

一文詳解JavaScript中執行上下文與執行堆疊(圖文結合)

上圖可以看到,我們明明給nameage賦值了,咋還會顯示undefined呢?這是因為執行上下文分為兩個部分,創建階段和執行階段。

  • 建立階段-執行上下文的初始化狀態,做一些準備工作
  • 執行階段-程式碼一行一行執行

以上就是建立階段的全域上下文概況,在建立階段JS引擎將會做以下幾件事:

  • window作為全域執行上下文物件
  • 建立this,this指向window
  • #給變數和函數安排記憶體空間
  • 變數賦值 undefined,函數宣告放入記憶體
  • 放入作用域鏈

#接下來才會進入了全域執行上下文的執行階段,也就是賦值階段,如下圖:

一文詳解JavaScript中執行上下文與執行堆疊(圖文結合)

需要注意的是執行上下文執行階段是一行一行執行的,如下圖所示:

一文詳解JavaScript中執行上下文與執行堆疊(圖文結合)

2.2 函數執行上下文

理解完全局執行上下文,函數執行上下文也我們只需要關注它與全局上下文之間的不同即可,兩者之間不同主要表現在以下三個方面:

  • 創建時機:全域執行上下文在執行JS檔之前就被創建,而函數執行上下文則是在函數呼叫時創建。
  • 建立頻率:全域上下文在程式碼剛開始被執行前創建一次,而函數執行上下文則由腳本裡函數呼叫次數決定,可以創建無數次。
  • 建立內容:全域執行上下文將window作為全域對象,而是函數執行上下文則是建立參數對象arguments;所建立的this也不會指向全域對象,而是取決於函數是如何呼叫的。

我們透過下面這個範例來看函數上下文不同階段的表現:

var name = '小明'
var age = 18
function showName(){
  return {
      name : name,
      age : age
  }
}

// 调用该函数
showName()

當我們呼叫showName函數時,就會進入到函數執行上下文的建立階段,函數執行上下文的場景如下:

一文詳解JavaScript中執行上下文與執行堆疊(圖文結合)

#接著就會進入到執行階段,這個階段函數內程式碼才會一行一行執行,在這個例子中,因為沒有涉及變數的修改,因此函數上下文的內容保持不變,執行完畢後,函數上下文的生命週期就結束了。

当我们调用showName函数时,在浏览器中运行状况:

一文詳解JavaScript中執行上下文與執行堆疊(圖文結合)

3 执行栈

我们看到当函数执行完后,其对应的执行上下文也随之消失了。这个消失的过程,我们叫它出栈——在JS代码执行过程中,JS引擎会为我们创建“执行上下文栈”。

在全局代码执行前,JS引擎为了管理执行上下文,确保程序的执行顺序。JS引擎会创建一个栈来管理所有的所有的执行上下文对象

因为函数上下文可能会存在多个,我们不可能保留所有的上下文。当一个函数执行完毕,其对应的上下文必须让出之前所占用的资源。因此上下文的建立和销毁,就对应了一个” 入栈 “和” 出栈 “的操作。

当我们调用一个函数的时候,就会把它的上下文推入调用栈里,执行完毕后出栈,随后再为新的函数进行入栈操作。

我们通过一个例子来看一下这个过程:

function testA(){
  console.log('执行第一个测试函数的逻辑');
  testB();
  console.log('再次执行第一个测试函数的逻辑');
}

function testB(){
  console.log('执行第二个测试函数的逻辑');
}

testA()

1、执行之前,全局上下文创建:

一文詳解JavaScript中執行上下文與執行堆疊(圖文結合)

2、testA调用,testA对应函数上下文创建:

一文詳解JavaScript中執行上下文與執行堆疊(圖文結合)

3、testB调用,testB对应函数上下文创建:

一文詳解JavaScript中執行上下文與執行堆疊(圖文結合)

4、testB执行完毕,对应上下文出栈,剩下testA和全局执行上下文:

一文詳解JavaScript中執行上下文與執行堆疊(圖文結合)

5、testA执行完毕,对应执行上下文出栈,此时只剩下全局上下文:

一文詳解JavaScript中執行上下文與執行堆疊(圖文結合)

在这整个过程里,调用栈的变化示意如下:

1一文詳解JavaScript中執行上下文與執行堆疊(圖文結合)

4 总结

  • 执行上下文是什么:代码执行前,Js引擎会创建代码的执行环境,代码的执行环境称作执行上下文,包含当前正在运行的代码以及帮助其执行的所有内容。

  • 全局执行上下文:(1)将window作为全局执行上下文对象(2)创建this,this 指向window(3)给变量和函数安排内存空间(4)变量赋值undefined,函数声明放入内存(5)放入作用域链

  • 全局与函数执行上下文不同:(1)全局:在文件执行前创建;函数:在函数调用时创建(2)全局:只创建一次;函数:调用几次创建几次(3)将window作为全局对象;函数:创建参数对象arguments,this指向调用者

  • 执行栈:管理所有的执行上下文对象

【相关推荐:javascript视频教程编程基础视频

以上是一文詳解JavaScript中執行上下文與執行堆疊(圖文結合)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.cn。如有侵權,請聯絡admin@php.cn刪除