1. 程式人生 > >JavaScript執行上下文

JavaScript執行上下文

想象 清空 上下文 AC 哪些 現在 span spa 包含

一直一來,對JavaScript的代碼執行順序,大部分人都會認為 順序執行

var foo = function () {

    console.log(‘foo1‘);

}

foo();  // foo1

var foo = function () {

    console.log(‘foo2‘);

}

foo(); // foo2

這裏看起來似乎都很合理,但是 沒有想象的那麽簡單

在看這一段代碼

function foo() {

    console.log(‘foo1‘);

}

foo();  

function foo() {

    console.log(‘foo2‘
); } foo();

兩次都會打印出foo2

這裏涉及到兩個問題 變量提升(之前寫過) 函數提升

JavaScript引擎並不是一行一行分析 執行程序 而是一段一段的執行 ,當執行一段代碼的時候,會進行一個“準備工作”,變量提升 函數提升 就是準備工作

這一段一段JavaScript是怎麽劃分的?

可執行代碼

這就要說到 JavaScript 的可執行代碼(executable code)的類型有哪些了?

就三種,全局代碼、函數代碼、eval代碼(轉義字符串為對象)。

舉個例子,當執行到一個函數的時候,就會進行準備工作,這裏的“準備工作”,
讓我們用個更專業一點的說法,就叫做"執行上下文(execution context)"。

執行上下文棧

接下來問題來了,我們寫的函數多了去了,如何管理創建的那麽多執行上下文呢?

所以 JavaScript 引擎創建了執行上下文棧(Execution context stack,ECS)來管理執行上下文

為了模擬執行上下文棧的行為,讓我們定義執行上下文棧是一個數組:

ECStack = [];

試想當 JavaScript 開始要解釋執行代碼的時候,最先遇到的就是全局代碼,

所以初始化的時候首先就會向執行上下文棧壓入一個全局執行上下文,

我們用 globalContext 表示它,並且只有當整個應用程序結束的時候,

ECStack 才會被清空,所以程序結束之前, ECStack 最底部永遠有個 globalContext:

ECStack = [
    globalContext     //全局代碼
];

現在 JavaScript 遇到下面的這段代碼了:

function fun3() {
    console.log(‘fun3‘)
}

function fun2() {
    fun3();
}

function fun1() {
    fun2();
}

fun1();

既然是棧,必定是先進後出 上面這段代碼可以這樣處理

//上面代碼執行完畢
//遇到fun1執行 加入棧
ECStack.push(<fun1> functionContext);
//fun1裏面執行fun2 加入棧
ECStack.push(<fun2> functionContext);
//fun1裏面執行fun2裏面執行fun3 加入棧 
ECStack.push(<fun3> functionContext);
//fun3裏面執行代碼 fun3 彈出棧
ECStack.pop();
//fun2 執行完畢 彈出棧
ECStack.pop();
//fun1 執行完畢 彈出棧
ECStack.pop();
// javascript接著執行下面的代碼,但是ECStack底層永遠有個globalContext

解答思考題

上一篇博客講了靜態作用域的問題,那麽使用 執行上下文棧的怎麽處理呢?

var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f();
}
checkscope();
ECStack.push(<checkscope> functionContext);
ECStack.push(<f> functionContext);
ECStack.pop();
ECStack.pop();
var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f;
}
checkscope()();
ECStack.push(<checkscope> functionContext);
ECStack.pop();
ECStack.push(<f> functionContext);
ECStack.pop();

雖然結果一樣但是代碼的執行卻並不一樣

為了更詳細講解兩個函數執行上的區別,我們需要探究一下執行上下文到底包含了哪些內容

今後更新

---恢復內容結束---

JavaScript執行上下文