執(zhí)行上下文可以理解為當前代碼的執(zhí)行環(huán)境,JavaScript中的運行環(huán)境大概包括三種情況:
- 全局環(huán)境:JavaScript代碼運行起來會首先進入該環(huán)境
- 函數(shù)環(huán)境:當函數(shù)被調(diào)用執(zhí)行時,會進入當前函數(shù)中執(zhí)行代碼
- eval
在代碼開始執(zhí)行時,首先會產(chǎn)生一個全局執(zhí)行上下文環(huán)境,調(diào)用函數(shù)時,會產(chǎn)生函數(shù)執(zhí)行上下文環(huán)境,函數(shù)調(diào)用完成后,它的執(zhí)行上下文環(huán)境以及其中的數(shù)據(jù)都會被銷毀,重新回到全局執(zhí)行環(huán)境,網(wǎng)頁關閉后全局執(zhí)行環(huán)境也會銷毀。其實這是一個壓棧出棧的過程,全局上下文環(huán)境永遠在棧底,而當前正在執(zhí)行的函數(shù)上下文在棧頂。
我們就用一個簡單的栗子來體會執(zhí)行上下文出棧入棧的過程:
var a = 1; //1.進入全局上下文環(huán)境
function out() {
var b = 2;
function inner() {
var c = 3;
console.log(a+b+c);
}
inner(); //3.進入inner函數(shù)上下文環(huán)境
}
out(); //2.進入out函數(shù)上下文環(huán)境
第一步:
當代碼開始執(zhí)行時就創(chuàng)建全局執(zhí)行上下文環(huán)境,全局上下文入棧。

第二步:
全局上下文入棧后,其中的代碼開始執(zhí)行,進行賦值、函數(shù)調(diào)用等操作,執(zhí)行到out()時,激活函數(shù)out創(chuàng)建自己的執(zhí)行上下文環(huán)境,out函數(shù)上下文入棧。

第三步:
out函數(shù)上下文入棧后,其中的代碼開始執(zhí)行,進行賦值、函數(shù)調(diào)用等操作,執(zhí)行到inner()時,激活函數(shù)inner創(chuàng)建自己的執(zhí)行上下文環(huán)境,inner函數(shù)上下文入棧。

第四步:
inner函數(shù)上下文入棧后,其中的代碼開始執(zhí)行,進行賦值、函數(shù)調(diào)用、打印等操作,由于里面沒有可以生成其他執(zhí)行上下文的需要,所有代碼執(zhí)行完畢后,inner函數(shù)上下文出棧。

第五步:
inner函數(shù)上下文出棧,又回到了out函數(shù)執(zhí)行上下文環(huán)境,接著執(zhí)行out函數(shù)中后面剩下的代碼,由于后面沒有可以生成其他執(zhí)行上下文的需要,所有代碼執(zhí)行完畢后,out函數(shù)上下文出棧。

第六步:
out函數(shù)上下文出棧后,又回到了全局執(zhí)行上下文環(huán)境,直到瀏覽器窗口關閉,全局上下文出棧。
總結(jié):
我們觀察一下入棧出棧的全部過程:

我們可以得到一些結(jié)論:
- 全局上下文在代碼開始執(zhí)行時就創(chuàng)建,只有唯一的一個,永遠在棧底,瀏覽器窗口關閉時出棧。
- 函數(shù)被調(diào)用的時候創(chuàng)建上下文環(huán)境。
- 只有棧頂?shù)纳舷挛奶幱诨顒訝顟B(tài),執(zhí)行其中的代碼。