原文出處
可執(zhí)行代碼
這就要說到 JavaScript 的可執(zhí)行代碼(executable code)的類型有哪些了?
其實(shí)很簡單盐须,就三種炎功,全局代碼盏筐、函數(shù)代碼狼纬、eval代碼。
舉個(gè)例子壁晒,當(dāng)執(zhí)行到一個(gè)函數(shù)的時(shí)候瓷们,就會進(jìn)行準(zhǔn)備工作,這里的“準(zhǔn)備工作”讨衣,讓我們用個(gè)更專業(yè)一點(diǎn)的說法换棚,就叫做"執(zhí)行上下文(execution context)"。
執(zhí)行上下文棧
接下來問題來了反镇,我們寫的函數(shù)多了去了固蚤,如何管理創(chuàng)建的那么多執(zhí)行上下文呢?
所以 JavaScript 引擎創(chuàng)建了執(zhí)行上下文棧(Execution context stack歹茶,ECS)來管理執(zhí)行上下文
為了模擬執(zhí)行上下文棧的行為夕玩,讓我們定義執(zhí)行上下文棧是一個(gè)數(shù)組:
ECStack = [];
試想當(dāng) JavaScript 開始要解釋執(zhí)行代碼的時(shí)候,最先遇到的就是全局代碼惊豺,所以初始化的時(shí)候首先就會向執(zhí)行上下文棧壓入一個(gè)全局執(zhí)行上下文燎孟,我們用 globalContext 表示它,并且只有當(dāng)整個(gè)應(yīng)用程序結(jié)束的時(shí)候尸昧,ECStack 才會被清空揩页,所以 ECStack 最底部永遠(yuǎn)有個(gè) globalContext:
ECStack = [
globalContext
];
現(xiàn)在 JavaScript 遇到下面的這段代碼了:
function fun3() {
console.log('fun3')
}
function fun2() {
fun3();
}
function fun1() {
fun2();
}
fun1();
當(dāng)執(zhí)行一個(gè)函數(shù)的時(shí)候,就會創(chuàng)建一個(gè)執(zhí)行上下文烹俗,并且壓入執(zhí)行上下文棧爆侣,當(dāng)函數(shù)執(zhí)行完畢的時(shí)候萍程,就會將函數(shù)的執(zhí)行上下文從棧中彈出。知道了這樣的工作原理兔仰,讓我們來看看如何處理上面這段代碼:
// 偽代碼
// fun1()
ECStack.push(<fun1> functionContext);
// fun1中竟然調(diào)用了fun2茫负,還要創(chuàng)建fun2的執(zhí)行上下文
ECStack.push(<fun2> functionContext);
// 擦,fun2還調(diào)用了fun3乎赴!
ECStack.push(<fun3> functionContext);
// fun3執(zhí)行完畢
ECStack.pop();
// fun2執(zhí)行完畢
ECStack.pop();
// fun1執(zhí)行完畢
ECStack.pop();
// javascript接著執(zhí)行下面的代碼忍法,但是ECStack底層永遠(yuǎn)有個(gè)globalContext