執(zhí)行上下文棧和執(zhí)行上下文

執(zhí)行上下文棧(Execution Context Stack);

在ECMASscript中的代碼有三種類型:global, function和eval。
每一種代碼的執(zhí)行都要依賴自身的上下文,其中g(shù)lobal函數(shù)的上下文中會包含很多function或者eval的實(shí)例。函數(shù)的每一次調(diào)用都會進(jìn)入函數(shù)執(zhí)行中的上下文,并且計(jì)算函數(shù)中變量等的值(有個(gè)疑問:如果下次再調(diào)用這個(gè)函數(shù)的時(shí)候,上次計(jì)算的變量還存在嗎?還是隨著函數(shù)的生命周期的結(jié)束而銷毀呢?)
,eval函數(shù)的每一次執(zhí)行,也會進(jìn)入eval執(zhí)行中的上下文,判斷應(yīng)該從何處獲取變量的值。
注意!一個(gè)function可能產(chǎn)生無限的上下文環(huán)境,也就是說函數(shù)的每一次調(diào)用都會產(chǎn)生新的上下文環(huán)境,甚至是遞歸函數(shù)。

function foo(bar){
.....
}
foo(1)
foo(2)
foo(3)
//相同的function 每次都會產(chǎn)生不同的上下文
foo1Context={
    變量對象VO:var bar=1;
   活動對象AO:。。。
}
foo2Context={
    變量對象VO:var bar=2;
   活動對象AO:。。。
}
foo2Context={
    變量對象VO:var bar=3;
   活動對象AO:。。。
}
//包含不同的狀態(tài),例如參數(shù)bar的值,(疑問:難道不同的變量對象就是不同的執(zhí)行上下文嗎?如果是這樣的話,那就是每次調(diào)用函數(shù)執(zhí)行上下都不同吧!)

???一個(gè)執(zhí)行上下文會激活其他的上下文,比如一個(gè)函數(shù)調(diào)用另一個(gè)函數(shù),或者在全局上下文內(nèi)調(diào)用全局函數(shù)(疑問:我一直以為全局上下文就是全局函數(shù)的上下文。。難道全局函數(shù)有自己的上下文嗎?),然后一層一層的調(diào)用下去,邏輯上來說,這種實(shí)現(xiàn)方式是棧,我們可以稱之為上下文堆棧。
激活其他上下文的某個(gè)上下文叫做調(diào)用者(caller),被激活的上下文叫做被調(diào)用者(callee),被調(diào)用者同時(shí)也可能是調(diào)用者.
???例如A的上下文激活B的上下文,A叫caller,B叫callee,B也可能是另一個(gè)callee的caller(B函數(shù)調(diào)用某些自身的內(nèi)部方法的意思吧),(例如一個(gè)全局上下文中的function又一次調(diào)用了它的內(nèi)部函數(shù)。)。
??當(dāng)一個(gè)caller激活了另一個(gè)callee,那么這個(gè)caller就暫停自身的執(zhí)行,然后將控制權(quán)交給callee,于是這個(gè)callee就被放入堆棧中,稱為進(jìn)行中的上下文(running/active execution context),(疑問:就比如

function a(){
   function b(){
   console.log("haha");
 }
return b;
}
a()

當(dāng)函數(shù)a執(zhí)行之后,函數(shù)a激活了函數(shù)b的上下文,現(xiàn)在a暫停執(zhí)行,程序進(jìn)入函數(shù)b執(zhí)行的意思嗎,然后b就被放到棧的最前端?)
??當(dāng)這個(gè)callee(被調(diào)用者)執(zhí)行完之后,會把控制權(quán)再次交給它的caller(調(diào)用它的函數(shù)也就是調(diào)用者),然后caller會在剛才暫停的地方繼續(xù)執(zhí)行。這個(gè)caller 結(jié)束之后會繼續(xù)觸發(fā)其他的上下文。一個(gè)callee可以用返回(return)或者拋出異常(exception)來結(jié)束自身的上下文。(就是說被調(diào)用的函數(shù)return之后就結(jié)束了)
??如下圖:
所有的ECMAScript的程序執(zhí)行都可以看做是一個(gè)執(zhí)行上下文堆棧[execution context (EC) stack]。棧的頂部就是出于激活狀態(tài)的上下文。
??當(dāng)一段程序開始的時(shí)候,會先進(jìn)入全局執(zhí)行上下文環(huán)境[global execution context],所以全局執(zhí)行上下文會最先被壓入棧的底部,
此時(shí)全局程序會開始初始化,初始化生成必要的對象[objects]和函數(shù)[functions],(我的理解:也就是在全局內(nèi)的變量和函數(shù)的聲明前置吧),
在此全局上下文執(zhí)行的過程中(就是運(yùn)行全局函數(shù)的過程中),它可能會激活一些方法(就時(shí)調(diào)用或執(zhí)行別的函數(shù)唄,當(dāng)然是已經(jīng)初始化過的),然后進(jìn)入他們的上下文環(huán)境,進(jìn)入他們的上下文環(huán)境之后,環(huán)境被激活,就被壓入執(zhí)行上下文堆棧[execution context (EC) stack]中,在這些初始化都結(jié)束之后,這個(gè)系統(tǒng)會等待一些事件(例如用戶的鼠標(biāo)點(diǎn)擊等),會觸發(fā)一些方法,然后進(jìn)入一個(gè)新的上下文環(huán)境。


Paste_Image.png

如下圖:有一個(gè)函數(shù)上下文“EC1″和一個(gè)全局上下文“Global EC”,下圖展現(xiàn)了從“Global EC”進(jìn)入和退出“EC1″時(shí)棧的變化:

Paste_Image.png

ECMAScript運(yùn)行時(shí)系統(tǒng)就是這樣管理代碼的執(zhí)行。

執(zhí)行上下文

每次當(dāng)控制器轉(zhuǎn)到ECMAScript可執(zhí)行代碼的時(shí)候,即會進(jìn)入到一個(gè)執(zhí)行上下文。執(zhí)行上下文(簡稱-EC)是ECMA-262標(biāo)準(zhǔn)里的一個(gè)抽象概念,用于同可執(zhí)行代碼(executable code)概念進(jìn)行區(qū)分。
??活動的執(zhí)行上下文組在邏輯上組成一個(gè)堆棧。堆棧底部永遠(yuǎn)都是全局上下文(global context),而頂部就是當(dāng)前(活動的)執(zhí)行上下文。堆棧在EC類型進(jìn)入和退出上下文的時(shí)候被修改(推入或彈出)。

原文:http://dmitrysoshnikov.com/ecmascript/javascript-the-core/
參考1:http://ued.ctrip.com/blog/?p=2795
參考2:http://www.cnblogs.com/ifishing/archive/2010/12/08/1900594.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容