執(zhí)行上下文棧(Execution Context Stack)潜叛;
在ECMASscript中的代碼有三種類型:global, function和eval。
每一種代碼的執(zhí)行都要依賴自身的上下文精盅,其中g(shù)lobal函數(shù)的上下文中會包含很多function或者eval的實例。函數(shù)的每一次調(diào)用都會進入函數(shù)執(zhí)行中的上下文镀首,并且計算函數(shù)中變量等的值(有個疑問:如果下次再調(diào)用這個函數(shù)的時候藤巢,上次計算的變量還存在嗎?還是隨著函數(shù)的生命周期的結(jié)束而銷毀呢撵溃?)
疚鲤,eval函數(shù)的每一次執(zhí)行,也會進入eval執(zhí)行中的上下文缘挑,判斷應(yīng)該從何處獲取變量的值集歇。
注意!一個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í)行上下都不同吧池充!)
???一個執(zhí)行上下文會激活其他的上下文,比如一個函數(shù)調(diào)用另一個函數(shù)缎讼,或者在全局上下文內(nèi)調(diào)用全局函數(shù)(疑問:我一直以為全局上下文就是全局函數(shù)的上下文收夸。。難道全局函數(shù)有自己的上下文嗎血崭?)卧惜,然后一層一層的調(diào)用下去厘灼,邏輯上來說,這種實現(xiàn)方式是棧咽瓷,我們可以稱之為上下文堆棧设凹。
激活其他上下文的某個上下文叫做調(diào)用者(caller),被激活的上下文叫做被調(diào)用者(callee),被調(diào)用者同時也可能是調(diào)用者.
???例如A的上下文激活B的上下文,A叫caller,B叫callee,B也可能是另一個callee的caller(B函數(shù)調(diào)用某些自身的內(nèi)部方法的意思吧)茅姜,(例如一個全局上下文中的function又一次調(diào)用了它的內(nèi)部函數(shù)闪朱。)。
??當(dāng)一個caller激活了另一個callee,那么這個caller就暫停自身的執(zhí)行钻洒,然后將控制權(quán)交給callee,于是這個callee就被放入堆棧中奋姿,稱為進行中的上下文(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í)行称诗,程序進入函數(shù)b執(zhí)行的意思嗎,然后b就被放到棧的最前端?)
??當(dāng)這個callee(被調(diào)用者)執(zhí)行完之后头遭,會把控制權(quán)再次交給它的caller(調(diào)用它的函數(shù)也就是調(diào)用者)寓免,然后caller會在剛才暫停的地方繼續(xù)執(zhí)行。這個caller 結(jié)束之后會繼續(xù)觸發(fā)其他的上下文任岸。一個callee可以用返回(return)或者拋出異常(exception)來結(jié)束自身的上下文再榄。(就是說被調(diào)用的函數(shù)return之后就結(jié)束了)
??如下圖:
所有的ECMAScript的程序執(zhí)行都可以看做是一個執(zhí)行上下文堆棧[execution context (EC) stack]。棧的頂部就是出于激活狀態(tài)的上下文享潜。
??當(dāng)一段程序開始的時候困鸥,會先進入全局執(zhí)行上下文環(huán)境[global execution context],所以全局執(zhí)行上下文會最先被壓入棧的底部,
此時全局程序會開始初始化剑按,初始化生成必要的對象[objects]和函數(shù)[functions]疾就,(我的理解:也就是在全局內(nèi)的變量和函數(shù)的聲明前置吧),
在此全局上下文執(zhí)行的過程中(就是運行全局函數(shù)的過程中)艺蝴,它可能會激活一些方法(就時調(diào)用或執(zhí)行別的函數(shù)唄猬腰,當(dāng)然是已經(jīng)初始化過的),然后進入他們的上下文環(huán)境猜敢,進入他們的上下文環(huán)境之后姑荷,環(huán)境被激活,就被壓入執(zhí)行上下文堆棧[execution context (EC) stack]中缩擂,在這些初始化都結(jié)束之后鼠冕,這個系統(tǒng)會等待一些事件(例如用戶的鼠標(biāo)點擊等),會觸發(fā)一些方法胯盯,然后進入一個新的上下文環(huán)境懈费。
如下圖:有一個函數(shù)上下文“EC1″和一個全局上下文“Global EC”,下圖展現(xiàn)了從“Global EC”進入和退出“EC1″時棧的變化:
ECMAScript運行時系統(tǒng)就是這樣管理代碼的執(zhí)行博脑。
執(zhí)行上下文
每次當(dāng)控制器轉(zhuǎn)到ECMAScript可執(zhí)行代碼的時候憎乙,即會進入到一個執(zhí)行上下文票罐。執(zhí)行上下文(簡稱-EC)是ECMA-262標(biāo)準里的一個抽象概念,用于同可執(zhí)行代碼(executable code)概念進行區(qū)分泞边。
??活動的執(zhí)行上下文組在邏輯上組成一個堆棧该押。堆棧底部永遠都是全局上下文(global context),而頂部就是當(dāng)前(活動的)執(zhí)行上下文繁堡。堆棧在EC類型進入和退出上下文的時候被修改(推入或彈出)沈善。
原文: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