亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

講清楚之執(zhí)行上下文

3fuyu / 3227人閱讀

摘要:棧底為全局上下文,棧頂為當(dāng)前正在執(zhí)行的上下文。位于棧頂?shù)纳舷挛膱?zhí)行完畢后會(huì)自動(dòng)出棧,依次向下直至所有上下文運(yùn)行完畢,最后瀏覽器關(guān)閉時(shí)全局上下文被銷毀。

講清楚之執(zhí)行上下文

標(biāo)簽 : javascript

什么是執(zhí)行上下文?

當(dāng) JavaScript 代碼執(zhí)行一段可執(zhí)行代碼時(shí),會(huì)創(chuàng)建對(duì)應(yīng)的上下文(execution context)并將該上下文壓入上下文棧(context stack)中。

上下文包含以下3個(gè)重要屬性:

name -
變量對(duì)象(VO, variable object) 當(dāng)前函數(shù)定義的變量、函數(shù)、參數(shù)
作用域鏈(Scope chain) 源代碼定義時(shí)形成的作用域鏈
this

上下文是一個(gè)抽象概念,為了便于理解我們假設(shè)上下文是一個(gè)對(duì)象并且包含VO、Scope、this這三個(gè)屬性:

function foo (c) {
  let a = 1
  let b = function () {}
}

// foo函數(shù)的上下文
fooContext = {
        VO: {
            arguments: { // 實(shí)參
              c: undefind,
              length: 0
            },
            a: 1, // 變量
            b: reference to function (){} // 函數(shù)
        },
        Scope: [VO, globalContext.VO], // 作用域鏈
        this: undefind // 非嚴(yán)格模式下為 this
    }

所以上下文是函數(shù)運(yùn)行時(shí)的環(huán)境或者說(shuō)是依賴資源的集合,它決定了函數(shù)運(yùn)行時(shí)可以獲取到哪些變量、函數(shù)。

執(zhí)行上下文(EC): 如果函數(shù)處于正在執(zhí)行狀態(tài)則該函數(shù)的上下文稱為執(zhí)行上下文, 與此同時(shí)如果函數(shù)處于非執(zhí)行狀態(tài)則為(普通)上下文。所以執(zhí)行上下文只是上下文的不同狀態(tài),本質(zhì)上它們沒有區(qū)別。

上下文棧

上下文棧又稱為執(zhí)行棧(ECS), 瀏覽器中 javascript 解析器本身是單線程的,即同一時(shí)間只能處理一個(gè)上下文及對(duì)應(yīng)的代碼段,所以 javascript 解析引擎使用上下文棧來(lái)管理上下文。所有的上下文創(chuàng)建后會(huì)保存在上下文棧隊(duì)列里。棧底為全局上下文,棧頂為當(dāng)前正在執(zhí)行的上下文。

一個(gè)上下文就是一個(gè)執(zhí)行單元, javascript 以棧的方式管理執(zhí)行單元。頁(yè)面初始化的時(shí)候首先會(huì)在棧底壓入全局上下文,然后根據(jù)規(guī)則執(zhí)行到可執(zhí)行函數(shù)時(shí)會(huì)將函數(shù)的上下文壓入上下文棧 中, 被壓入的上下文包含有該函數(shù)運(yùn)行時(shí)所需的資源(變量對(duì)象、作用域鏈、this),這些資源提供給函數(shù)運(yùn)行時(shí)的表達(dá)式使用。

執(zhí)行上下文可以理解為函數(shù)運(yùn)行時(shí)的環(huán)境。同時(shí)執(zhí)行上下文也是一個(gè)不可見的概念。

javascript 中有3種運(yùn)行環(huán)境:

全局環(huán)境: 在瀏覽器中是window, 在 node 環(huán)境中是global,當(dāng)頁(yè)面初始化時(shí)會(huì)將全局上下文壓入上下文棧;

函數(shù)環(huán)境: 當(dāng)函數(shù)被調(diào)用執(zhí)行時(shí)會(huì)收集該函數(shù)的資源,創(chuàng)建上下文并壓入上下文棧;

eval環(huán)境,棄用

一個(gè)運(yùn)行環(huán)境會(huì)對(duì)應(yīng)一個(gè)上下文。位于棧頂?shù)纳舷挛膱?zhí)行完畢后會(huì)自動(dòng)出棧,依次向下直至所有上下文運(yùn)行完畢,最后瀏覽器關(guān)閉時(shí)全局上下文被銷毀。為了好理解來(lái)舉個(gè)栗子:

let i = 0
function foo () {
    i++
    console.log(i, "foo")
}
function too () {
    i++
    console.log(i, "too")
    foo()
}
function don () {
    i++
    console.log(i, "don")
    too()
}
don()

 // 1 "don"
 // 2 "too"
 // 3 "foo"

上面代碼的邏輯就是先執(zhí)行don(),然后是too()、foo()。執(zhí)行到foo()時(shí)的上下文棧是這樣的:

我們假設(shè)上下文棧為一個(gè)數(shù)組:ECStack

ECStack = []

javascript 載入完成后首先解析執(zhí)行的是全局代碼,所以初始化的時(shí)候會(huì)向上下文棧中 push 全局上下文,我們用globalContext來(lái)表示。

ECStack = [
    globalContext
]

全局作用域在整個(gè)代碼運(yùn)行階段會(huì)一直存在,直至頁(yè)面關(guān)閉時(shí) ECStack 會(huì)被請(qǐng)空,從而globalContext則被銷毀。

全局上下文創(chuàng)建的時(shí)候進(jìn)行變量提升、生成變量對(duì)象等操作,而后會(huì)執(zhí)行當(dāng)前上下文中的可執(zhí)行代碼(函數(shù)、表達(dá)式)。遇到函數(shù)調(diào)用的時(shí)候會(huì)向上下文棧中push該函數(shù)的上下文。

function foo () {
    console.log("foo")
}
function too () {
    console.log("too")
    foo()
}
function don () {
    too()
}
don()

執(zhí)行邏輯可以理解為:

執(zhí)行到 don(), 解析 don函數(shù)內(nèi)部代碼

生成 don 函數(shù)的上下文(vo、Scope chain、this)

壓入 don 的上下文到 ECStack

執(zhí)行 don 函數(shù)體內(nèi)部的表達(dá)式

執(zhí)行 too()

生成 too 函數(shù)的上下文(vo、Scope chain、this)

壓入 too 的上下文到 ECStack

...

javascript 解析器不斷遞歸直到 foo 函數(shù)執(zhí)行完...foo 函數(shù)上下文被彈出...然后回溯到globalContext上下文...等待...當(dāng)事件的回調(diào)函數(shù)被激活后,執(zhí)行回調(diào)函數(shù)。( 這里涉及到 javascript 的執(zhí)行機(jī)制和事件循環(huán),請(qǐng)關(guān)注后續(xù)文章^_^)

執(zhí)行邏輯的偽代碼如下:

// 偽代碼

// don()
ECStack.push( functionContext);

// 在don中調(diào)用了too, push too的上下文到上下文棧里
ECStack.push( functionContext);

// 在too中調(diào)用了foo, push foo的上下文到上下文棧里
ECStack.push( functionContext);

// foo執(zhí)行完畢, 彈出上下文
ECStack.pop();

// too執(zhí)行完畢, 彈出上下文
ECStack.pop();

// don執(zhí)行完畢, 彈出上下文
ECStack.pop();

// 非全局上下文執(zhí)行完畢被彈出后會(huì)一直停留在全局上下文里,直至頁(yè)面關(guān)閉
需要注意的是,上下文與作用域(scope)是不同的概念。上下文是一個(gè)運(yùn)行時(shí)概念,瀏覽器運(yùn)行后執(zhí)行 js 代碼,將不同的上下文加入上下文棧中,頂層的上下文對(duì)應(yīng)的代碼塊執(zhí)行完后又將該上下文銷毀。 而作用域是一個(gè)靜態(tài)概念,根據(jù)所在代碼片段的位置及詞法關(guān)系確立的,不管瀏覽器運(yùn)行與否,源代碼的作用域關(guān)系、變量的訪問權(quán)限依然不變。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/95233.html

相關(guān)文章

  • 講清楚之 javascript 參數(shù)傳值

    摘要:講清楚之參數(shù)傳值參數(shù)傳值是指函數(shù)調(diào)用時(shí),給函數(shù)傳遞配置或運(yùn)行參數(shù)的行為,包括通過(guò)進(jìn)行傳值。所以對(duì)的賦值會(huì)改變上下文棧中標(biāo)識(shí)符保存的具體值此時(shí)如果使用的是按引用傳遞,則變量所指向的對(duì)象因該也被賦值為。 講清楚之 javascript 參數(shù)傳值 參數(shù)傳值是指函數(shù)調(diào)用時(shí),給函數(shù)傳遞配置或運(yùn)行參數(shù)的行為,包括通過(guò)call、apply 進(jìn)行傳值。 在實(shí)際開發(fā)中,我們總結(jié)javascript參數(shù)傳...

    itvincent 評(píng)論0 收藏0
  • 講清楚之 javascript中的this

    摘要:講清楚之中的這一節(jié)來(lái)探討。所以當(dāng)函數(shù)作為構(gòu)造函數(shù)調(diào)用,則函數(shù)內(nèi)部的綁定到該函數(shù)上。在通過(guò)構(gòu)造函數(shù)實(shí)例化對(duì)象時(shí),對(duì)象內(nèi)部的也同樣指向該實(shí)例對(duì)象。 講清楚之 javascript中的this 這一節(jié)來(lái)探討this。 在 javascript 中 this 也是一個(gè)神的存在,相對(duì)于 java 等語(yǔ)言在編譯階段確定,而在 javascript 中, this 是動(dòng)態(tài)綁定,也就是在運(yùn)行期綁定的。...

    selfimpr 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<