1 回答

TA貢獻(xiàn)1779條經(jīng)驗(yàn) 獲得超6個(gè)贊
博士
它們都是Environment Record
.
LexicalEnvironment
只是執(zhí)行上下文的一個(gè)組成部分(函數(shù)不能有LexicalEnvironment
),并且在調(diào)用函數(shù)時(shí),LexicalEnvironment
會(huì)為當(dāng)前上下文創(chuàng)建一個(gè)新的,其[[OuterEnv]]
字段被設(shè)置為 Function[[Environment]]
字段。
如果它是 Javascript,我想它會(huì)是:
function?handleInvokeFunction(func)?{ ????const?localEnv?=?new?EnvironmentRecord(); ????localEnv.set('[[OuterEnv]]',?func['[[Environment]]']) ????calleeContext.lexicalEnvironment?=?localEnv; }
免責(zé)聲明:我不是這方面的專家。我只是想給你一個(gè)整體的想法,同時(shí)等待真正的專家在這里插話。
環(huán)境記錄
Environment Records,用于記錄(雙關(guān)語(yǔ)意),包含執(zhí)行功能所需的所有信息。例如,對(duì)于函數(shù),它們包含變量聲明和this
值。當(dāng)然,這是過(guò)于簡(jiǎn)單化了[src]。
環(huán)境記錄是一種規(guī)范類型,用于定義標(biāo)識(shí)符與特定變量和函數(shù)的關(guān)聯(lián)。
每次評(píng)估此類代碼時(shí),都會(huì)創(chuàng)建一個(gè)新的環(huán)境記錄來(lái)記錄該代碼創(chuàng)建的標(biāo)識(shí)符綁定。
關(guān)于環(huán)境記錄的一件有趣的事情是,它們負(fù)責(zé)允許訪問父變量,例如:
//?Environment?Record?"EnvA" const?hello?=?"world"; if?(1)?{ ????//?Environment?Record?"EnvB" ????console.log(hello); } //?outputs:?world
那是因?yàn)樗麄冇幸粋€(gè)名為 的字段[[OuterEnv]]
,它指向父環(huán)境。所以在上面的例子中,[[OuterEnv]]
“EnvB”字段被設(shè)置為“EnvA”?[src]。
每個(gè)環(huán)境記錄都有一個(gè)
[[OuterEnv]]
字段,該字段要么為空,要么是對(duì)外部環(huán)境記錄的引用。
每次運(yùn)行時(shí)遇到一個(gè)新的代碼塊,它都會(huì)執(zhí)行以下步驟[src]:
創(chuàng)建一個(gè)新的環(huán)境記錄。
將該新環(huán)境的字段設(shè)置
[[OuterEnv]]
為舊(當(dāng)前活動(dòng))環(huán)境。返回新環(huán)境
執(zhí)行上下文
為了對(duì)所有塊執(zhí)行此操作,使用了執(zhí)行上下文堆棧,它幾乎類似于堆棧跟蹤?[src]。不同之處在于,它不會(huì)僅在進(jìn)入和退出函數(shù)時(shí)推送和彈出(就像堆棧跟蹤那樣),它只會(huì)更改進(jìn)入或退出代碼塊時(shí)的最頂層條目(如 if 塊)。
執(zhí)行上下文是一種規(guī)范設(shè)備,用于跟蹤 ECMAScript 實(shí)現(xiàn)對(duì)代碼的運(yùn)行時(shí)評(píng)估。
執(zhí)行上下文堆棧用于跟蹤執(zhí)行上下文。
執(zhí)行上下文有一個(gè)LexicalEnvironment
組件。需要跟蹤該特定代碼塊中的變量。
LexicalEnvironment:標(biāo)識(shí)環(huán)境記錄,用于解析代碼在此執(zhí)行上下文中所做的標(biāo)識(shí)符引用。
LexicalEnvironment
?是一個(gè)環(huán)境記錄,所以它有一個(gè)[[OuterEnv]]
字段,這是運(yùn)行時(shí)將相應(yīng)更改的內(nèi)容。
LexicalEnvironment
不屬于函數(shù)對(duì)象。它只屬于一個(gè)執(zhí)行上下文。
正在運(yùn)行的執(zhí)行上下文表示運(yùn)行時(shí)當(dāng)前正在執(zhí)行的代碼塊[src]。
正在運(yùn)行的執(zhí)行上下文始終是此堆棧的頂部元素。
為了擴(kuò)展上述步驟,當(dāng)輸入一個(gè)新的代碼塊時(shí),這就是實(shí)際發(fā)生的事情[src]:
創(chuàng)建具有適當(dāng)值的新環(huán)境記錄
[[OuterEnv]]
(與之前相同的步驟)。使用新的環(huán)境記錄作為運(yùn)行記錄。
評(píng)估塊內(nèi)的所有行。
恢復(fù)到以前的環(huán)境記錄。
返回結(jié)果并退出塊。
評(píng)論前面的例子,這就是會(huì)發(fā)生的事情:
// This is Environment Record "EnvA".
// The [[OuterEnv]] field for "EnvA" is null.
// The running context LexicalEnvironment is "EnvA".
const hello = "world";
if (1) {
? ? // Found new block
? ? // Create a new Environment Record "EnvB".
? ? // Set the "EnvB" [[OuterEnv]] field to
? ? // the running context LexicalEnvironment.
? ? // In this case, its "EnvA".
? ? // Change the running context LexicalEnvironment to "EnvB".
? ??
? ? // Evaluate all lines in the body using the new?
? ? // running context LexicalEnvironment.
? ? // In this case, its "EnvB".
? ??
? ? console.log(hello);
? ??
? ? // Restore the previous running context LexicalEnvironment.
? ? // Return the result.
}
// The running context LexicalEnvironment is Environment Record "A".
// Since the inner block restored before returning, it didn't change.
[[環(huán)境]]
不過(guò),還沒有提到功能。這是不同的,因?yàn)楹瘮?shù)可以在聲明的范圍之外執(zhí)行。
那就是[[Environment]]
出現(xiàn)的地方。
[[Environment]]:函數(shù)被關(guān)閉的環(huán)境記錄。在評(píng)估函數(shù)的代碼時(shí)用作外部環(huán)境。
當(dāng)塊內(nèi)有函數(shù)時(shí),runningLexicalEnvironment
被存儲(chǔ)為[[Environment]]
函數(shù)對(duì)象的字段。
調(diào)用該函數(shù)時(shí),該[[Environment]]
字段用作[[OuterEnv]]
。
這就像該函數(shù)將它可以訪問的所有變量存儲(chǔ)在內(nèi)部[[Environment]]
,并且在調(diào)用時(shí),它可以使用再次訪問它們[[Environment]]
。
與普通塊的另一個(gè)區(qū)別是,在這種情況下,不是更改正在運(yùn)行的執(zhí)行上下文,而是創(chuàng)建一個(gè)新的并將其推送到堆棧。
現(xiàn)在,嘗試使用一個(gè)簡(jiǎn)單的代碼:
// This is Environment Record "EnvA".
// The [[OuterEnv]] field for "EnvA" is null.
// The running context LexicalEnvironment is "EnvA".
const hello = "world";
// Found a function, store the running context?
// into its [[Environment]] field, and do nothing else.
function foo() {
? ? // This block runs only after invoking bar().
? ??
? ? // Create a new executing context "calleeContext".
? ? // Create a new Environment Record "EnvB".
? ? // Set the "EnvB" [[OuterEnv]] field, to the value
? ? // stored inside [[Environment]]. In this case, its "EnvA".
? ? // Set the LexicalEnvironment of "calleeContext" to "EnvB".
? ? // Push "calleeContext" to the execution context stack.
? ? // That makes "calleeContext" the running execution context.
? ??
? ? // Evaluate all lines in the body
? ? // using "calleeContext" LexicalEnvironment.
? ? // In this case, its "EnvB".
? ? // If a function is found here, set its
? ? // [[Environment]] to "calleeContext" LexicalEnvironment.
? ??
? ? console.log(hello); // works because `hello` was in "EnvA"
? ??
? ? // Pop "calleeContext" from the execution context stack.
? ? // "calleeContext" is no longer the running execution context.
? ??
? ? // Return the result.
}
const bar = foo;
bar();
// The [[Environment]] of `bar` is still "EnvA".
// The running context LexicalEnvironment is still "EnvA".
由于該示例在聲明函數(shù)的同一環(huán)境中調(diào)用該函數(shù),因此它實(shí)際上并未使用“閉包”,但您可能已經(jīng)明白了。
綜上所述
盡管都是和[[Environment]]
,但它們用于不同的事物。LexicalEnvironment
Environment Records
[[Environment]]
保存LexicalEnvironment
函數(shù)聲明的位置。
LexicalEnvironment
是執(zhí)行上下文的一個(gè)組成部分,它存儲(chǔ)有關(guān)該特定代碼塊中的變量的信息。
添加回答
舉報(bào)