執(zhí)行上下文
1. 定義
執(zhí)行上下文就是js代碼被解析和執(zhí)行時(shí)所在環(huán)境的抽象概念,js的所有代碼都是在執(zhí)行上下文中運(yùn)行。
2. 類型
執(zhí)行上下文有三種類型:
全局執(zhí)行上下文:
一個(gè)程序中只能存在一個(gè)全局執(zhí)行上下文,不在任何函數(shù)中的代碼都在全局執(zhí)行上下文中。函數(shù)執(zhí)行上下文:
每次調(diào)用函數(shù)都會(huì)創(chuàng)建一個(gè)新的執(zhí)行上下文,一個(gè)程序中可以包含任意多個(gè)函數(shù)執(zhí)行上下文eval執(zhí)行上下文
3. 內(nèi)容
執(zhí)行上下文也是一個(gè)對(duì)象!那么這個(gè)對(duì)象中包括了哪些內(nèi)容呢
每一個(gè)執(zhí)行上下文都包括三個(gè)屬性:
- 活動(dòng)對(duì)象(variable object)
- 作用域鏈(scope chain)
- this對(duì)象
4. 執(zhí)行棧
存儲(chǔ)執(zhí)行上下文的數(shù)據(jù)結(jié)構(gòu)是堆棧,它是一種先進(jìn)后出的數(shù)據(jù)結(jié)構(gòu), 稱其為執(zhí)行棧。
存儲(chǔ)過(guò)程
1.當(dāng)js引擎首次讀取讀取腳本時(shí),便會(huì)創(chuàng)建一個(gè)全局執(zhí)行上下文,并將其壓入棧底,
- 如果執(zhí)行期間碰到了函數(shù),便會(huì)創(chuàng)建一個(gè)新的函數(shù)執(zhí)行上下文。
- 在執(zhí)行2中函數(shù)的時(shí)候又碰到了一個(gè)函數(shù),便會(huì)再次創(chuàng)建一個(gè)新的執(zhí)行上下文。。。
- 當(dāng)某一個(gè)函數(shù)執(zhí)行完畢,也將其執(zhí)行上下文中堆棧中出棧,并將控制權(quán)交還給前一個(gè)執(zhí)行上下文。
-
最終所有函數(shù)執(zhí)行上下文出棧,僅剩下全局之執(zhí)行上下文也出棧,程序執(zhí)行完畢。應(yīng)該是當(dāng)瀏覽器被關(guān)閉,全局執(zhí)行上下文才會(huì)被銷毀!
5.舉個(gè)例子
function f1() {
console.log('f1')
}
function f2() {
f1()
console.log('f2')
}
function f3() {
f2()
}
f3()
我們假設(shè)一開始的上下文執(zhí)行棧為 []
當(dāng)上例代碼加載時(shí),js引擎會(huì)創(chuàng)建一個(gè)全局執(zhí)行上下文并壓入棧底。
更新執(zhí)行棧為:
[[全局執(zhí)行上下文]
]執(zhí)行到了函數(shù)f3,創(chuàng)建f3的執(zhí)行上下文
[[f3的執(zhí)行上下文]
[全局執(zhí)行上下文]
]執(zhí)行f3的過(guò)程中,碰到了f2!趕緊創(chuàng)建f2的執(zhí)行上下文
[[f2的執(zhí)行上下文]
[f3的執(zhí)行上下文]
[全局執(zhí)行上下文]
]執(zhí)行f2的過(guò)程中,又碰到了f1!又趕緊創(chuàng)建f1的執(zhí)行上下文
[[f1的執(zhí)行上下文]
[f2的執(zhí)行上下文]
[f3的執(zhí)行上下文]
[全局執(zhí)行上下文]
]f1執(zhí)行完畢了 就把f1的執(zhí)行上下文出棧吧,并丟還給f2的執(zhí)行上下文
[[f1的執(zhí)行上下文]
[f2的執(zhí)行上下文]
[f3的執(zhí)行上下文]
[全局執(zhí)行上下文]
]、f2也執(zhí)行完了, 還給f3吧
[[f1的執(zhí)行上下文]
[f2的執(zhí)行上下文]
[f3的執(zhí)行上下文]
[全局執(zhí)行上下文]
]、f3委屈的將執(zhí)行權(quán)還給了全局執(zhí)行上下文
[[f1的執(zhí)行上下文]
[f2的執(zhí)行上下文]
[f3的執(zhí)行上下文]
[全局執(zhí)行上下文]
]、全局執(zhí)行上下文結(jié)束,全部出棧 執(zhí)行棧為
[]
[[f1的執(zhí)行上下文]
[f2的執(zhí)行上下文]
[f3的執(zhí)行上下文]
][全局執(zhí)行上下文]