重學JavaScript深刻理解系列(一)

JavaScript深刻理解——執行上下文(Execution Context)

定義

每當控制器到達ECMAScript可執行代碼的時候,控制器就進入了一個執行上下文。 執行上下文(簡稱:EC) 之後出去要說EC由於夠逼格😏 EC是個抽象的概念,ECMA-262標準中用它來區分不一樣類型的可執行代碼。數組

標準中並無從技術實現的角度來定義可執行上下文的具體結構和類型;這是現實標準的ECMAScript引擎所要考慮的問題。瀏覽器

一系列活動的執行上下文從邏輯上造成一個棧。棧底是全局上下文,棧頂是當前(活動的)執行上下文。當在不一樣的執行上下文切換的時候,棧會被修改(經過壓棧或者退棧的形式)。 bash

可執行代碼類型

可執行代碼類型和執行上下文相關。有的時候,當提到代碼類型的時候,其實就是在說執行上下文。

舉個🌰 咱們將執行上下文的棧以數組的形式來表示ecmascript

ECStask =[];
複製代碼

每次控制器進入一個函數(哪怕該函數被遞歸調用或者做爲構造器),都會發生壓棧的操做。內置eval函數工做的時候也不例外 ide

全局代碼

這類代碼是在"程序"級別上被處理的:好比,加載一個外部的js文件或者內聯的js代碼(被包含在script標籤內).全局代碼不包含任何函數體內的代碼。 在初始化的時候(程序開始的時候) ECStack以下
ECStask =[
    globalContext
];
複製代碼

函數代碼

一旦控制器進入函數代碼(各種函數),就會有新的元素會被壓棧到ECStack。

要注意的是:實體函數代碼並不包括內部函數代碼函數

以下所示,咱們調用一個函數,該函數遞歸調用本身一次: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代碼

說道Eval代碼就比較有意思了。這裏要提到一個叫作調用上下文的概念,好比:調用eval函數時候的上下文,就是一個調用上下文,eval函數中執行的動做(例如: 變量聲明或者函數聲明)會影響整個調用上下文:
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深刻理解系列(六)

相關文章
相關標籤/搜索