每當控制器到達ECMAScript可執行代碼的時候,控制器就進入了一個執行上下文。 執行上下文(簡稱:EC) 之後出去要說EC由於夠逼格😏 EC是個抽象的概念,ECMA-262標準中用它來區分不一樣類型的可執行代碼。數組
標準中並無從技術實現的角度來定義可執行上下文的具體結構和類型;這是現實標準的ECMAScript引擎所要考慮的問題。瀏覽器
一系列活動的執行上下文從邏輯上造成一個棧。棧底是全局上下文,棧頂是當前(活動的)執行上下文。當在不一樣的執行上下文切換的時候,棧會被修改(經過壓棧或者退棧的形式)。 bash
舉個🌰 咱們將執行上下文的棧以數組的形式來表示ecmascript
ECStask =[];
複製代碼
每次控制器進入一個函數(哪怕該函數被遞歸調用或者做爲構造器),都會發生壓棧的操做。內置eval函數工做的時候也不例外 ide
ECStask =[
globalContext
];
複製代碼
要注意的是:實體函數代碼並不包括內部函數代碼。函數
以下所示,咱們調用一個函數,該函數遞歸調用本身一次:post
(function foo(bar){
if(bar){
return;
}
foo(true);
})();
複製代碼
以後, ECStack就被修改爲以下所示:ui
// 首先激活foo函數
ECStack = [
functionContext
globalContext
]
// 遞歸激活foo函數
ECStack = [
functionContext - recursively
functionContext
globalContext
]
複製代碼
每次函數返回,退出當前活動的執行上下文時,ECStack就會被執行對應的退棧操做--(先進後出和傳統的棧實現一致)。spa
一樣的,當拋出未捕獲的異常時,也會退出一個或者多個執行上下文,ECStack也會作相應的退棧操做。翻譯
待這些代碼完成以後,ECStack中就只剩下一個執行上下文(globalContext)直到整個程序結束。
eval('var x = 10');
(function foo(){
eval('var y = 20');
})();
alert(x); //10
alert(y); // 'y' is not defined
複製代碼
ECStack 會被修改成:
ECStack = [
globalContext
]
// eval('var x = 10');
ECStack.push(
evalContext,
callingContext: globalContext
)
// eval exited context
ECStack.pop();
// foo function call
ECStack.push(functionContext);
// eval('var y = 20');
ECStack.push(
evalContext,
callingContext: functionContext
);
// return from eval
ECStack.pop();
// return from foo
ECStack.pop();
複製代碼
在1.7以上版本SpiderMonkey的實現中(Firefox, Thunderbird瀏覽器內置的JS引擎),容許在調用eval函數的時候,將調用上下文做爲的第二個參數傳遞給eval函數。所以,若是傳入的調用上下文存在的話,就有可能會影響該上下文中原有的私有變量
function foo(){
var x = 1;
return function() {
alert(x);
}
}
var bar = foo();
bar(); // 1
eval('x = 2', bar); // 傳遞上下文,影響了內部變量var x
bar(); // 2
複製代碼
ps: 雖然都是別人翻譯好的可是由於以爲寫的好仍是想敲一遍~也方便本身查閱
重學JavaScript深刻理解系列(二)
重學JavaScript深刻理解系列(三)
重學JavaScript深刻理解系列(四)
重學JavaScript深刻理解系列(五)
重學JavaScript深刻理解系列(六)