你們都知道js是單線程的,因此這就意味着它一次只能作一個件事情,而一個js的文件中必然會執行多個操做,好比全局代碼,函數代碼,每執行一次就會生成多個執行上下文,js中採用棧的方式來處理它,你們都知道棧的執行是先進的後出,所以全局的執行上下文永遠是最底層的,在程序執行完畢的時候出棧
數組
咱們舉個栗子來模擬一下執行上下文棧的流程
bash
<script>
function EC(){
let b = 1
console.log(b)
}
EC()
</script>
複製代碼
1.
首先咱們把執行上下文棧假設成一個數組,這樣比較好理解,當代碼還未執行時,執行上文棧是空的函數
ECStack = [];
複製代碼
2.
當上述代碼剛進入script標籤後,就進入了一個全局的環境,此時的全局環境的執行上下文就會入棧,咱們用globalContext來表示全局的執行上下文ui
ECStack = [
globalContext
]
複製代碼
3.
咱們接着來看咱們的代碼,此時js遇到了以下代碼this
function EC(){
let b = 1
console.log(b)
}
複製代碼
此時編譯器遇到了函數,它會生成一個函數的執行上下文並壓入棧中,咱們用ECContext來表示該函數的執行上下文spa
//此時的ECStack中多了一個ECContext,而globalContext被壓到了棧底
ECStack = [
ECContext,
globalContext
]
複製代碼
4.
再接着看咱們的代碼,此時該執行函數EC了,此時EC的執行上下文內部會作一些處理,這個咱們後面會講到,如今咱們只關心執行上文棧是怎麼操做的線程
//當EC函數執行完後,在棧頂的ECContext會彈出,棧底的globalContext會到棧頂的位置,此時的ECStack
ECStack = [
globalContext
]
複製代碼
當該js被銷燬的時候,globalContext會彈出棧,ECStack被回收,至此一個完整的js就走完了指針
你們可能會有些疑問,頻頻提到的執行上下文究竟作了些什麼?
code
什麼是執行上下文?來看定義
對象
一段能夠執行的代碼在被執行的時候,會建立一個執行上下文,執行上下文,能夠理解爲當前代碼的執行環境
那麼什麼是可執行代碼呢?
對於每一個執行上下文都有三個重要的屬性,它們分別是
咱們先來分析下變量對象Variable object,VO究竟是什麼
執行上下文在建立的時候會先建立變量對象vo,VO保存了函數中的全部形參,實參,局部變量,this指針等函數執行時的函數內部的數據狀況(此時尚未執行代碼),在全局執行上下文中叫作變量對象VO,在函數執行上下文中叫作活動對象AO,其實兩個是同樣的,具體以下
1.函數的形參和實參(若是是函數上下文)
2.函數的聲明,function max()
3.變量的聲明,如 var a
咱們還用分析執行上下文棧時的代碼改造下來舉栗子
function EC(a) {
var b = 1
console.log(b)
console.log(a)
var c = function (){}
function c(){}
}
EC(2)
複製代碼
此時的AO爲,函數尚未被執行
AO = {
arguments:{
0:2,
length: 1
},
a:2,
b:undefined,
c:undefined,
d:reference to function d(){}
}
複製代碼
當執行EC函數的代碼時,AO會依次賦值,當執行完畢後,此時的AO
AO = {
arguments:{
0:2,
length: 1
},
a:2
b:1,
c:reference to FunctionExpression "c"
d:reference to function c(){}
}
複製代碼
至此變量對象的建立過程就完結了