JavaScript 中的執行上下文和執行棧

執行上下文概念

執行上下文就是評估和執行javascript代碼的環境的抽象概念.每當javascript運行的時候,它都是在執行上下文中運行javascript

執行上下文的類型

  1. 全局執行上下文: 這是默認的上下文,任何不在函數內部的代碼都在全局上下文中.它會執行兩件事: 建立一個全局window,而且設置this的值指向這個window. 一個程序中只有一個全局執行上下文
  2. 函數執行上下文: 每當一個函數被調用時, 都會爲該函數建立一個新的上下文. 每一個函數都有它本身的執行上下文, 不過都是在函數被調用時建立的. 函數上下文能夠有多個, 每當一個新的執行上下文建立時, 它會按照定義的順序執行一系列的步驟.

執行棧

是一種擁有後進先出數據結構的棧, 被用來儲存代碼運行時建立的全部執行上下文
爲了模擬執行上下文棧的行爲,讓咱們定義執行上下文棧是一個數組:java

ECStack = [];

當javascript引擎第一次遇到你的腳本時.它會建立一個全局的執行上下文,而且壓入當前執行棧,也就是數組ECStack中.數組

ECStack = [
    globalContext
];

每當引擎遇到一個函數調用.它會爲該函數建立一個新的執行上下文而且壓入當前執行棧的頂部.數據結構

引擎會執行那些執行上下文位於棧頂的函數。當該函數執行結束時,執行上下文從棧中彈出,控制流程到達當前棧中的下一個上下文
如今javascript遇到下面的這段代碼:函數

function fun3() {
    console.log('fun3')
}
function fun2() {
    fun3();
}
function fun1() {
    fun2();
}
fun1();
// fun1()
ECStack.push(<fun1> functionContext);
// fun1中調用了fun2,還要建立fun2的上下文
ECStack.push(<fun2> functionContext);
// fun2調用了fun3 
ECStack.push(<fun3> functionContext);
// fun3 執行完畢
ECStack.pop();
// fun2 執行完畢
ECStack.pop();
// fun1 執行完畢
ECStack.pop();

思考題:this

// 比較下面兩段代碼,試述兩段代碼的不一樣之處
var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f();
}
checkscope(); // 

// B---------------------------
var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f;
}
checkscope()();

上面兩端代碼輸出值是同樣的, 都是local scope
可是執行上下文棧的變化不同
第一段代碼code

ECStack.push(<checkscope> functionContext)
ECStack.push(<f> functionContext)
ECStack.pop()
ECStack.pop()

模擬第二段代碼ip

ECStack.push(<checkscope> functionContext)
ECStack.pop()
ECStack.push(<f> functionContext)
ECStack.pop()

做用域

做用域是程序源代碼中定義變量的區域
做用域規定了若是查找變量,也就是肯定當前執行代碼對變量的訪問權限.
詞法做用域: javascript採用的是詞法做用域 也就是靜態做用域, 函數的做用域是在定義的時候就決定了
動態做用域: 函數的做用域是在函數調用的時候才決定的作用域

看下面例子io

var value = 1;
function foo() {
    console.log(value);
}
function bar() {
    var value = 2;
    foo();
}
bar();

假如javascript採用靜態做用域.
執行foo函數,先從foo函數內部查找是否有局部變量value.若是沒有,就根據書寫的位置,查找上面一層代碼. 也就是value等於1. 因此結果會打印1

假設javascript採用動態做用域.執行foo函數.依然是從foo函數內部查找是否有局部變量value.若是沒有.就從調用函數的做用域. 也就是bar函數內部查找value變量,因此打印2

相關文章
相關標籤/搜索