簡體   English   中英

let 和 const 如何適應當前的執行上下文? 他們是否每次都創建一個新的?

[英]How do let and const fit in the current execution context? Do they create a new one every time?

所以,我一直在閱讀一些關於閉包、作用域、詞法環境和執行上下文的東西。 據我了解,當前執行上下文有一個詞法環境和一個變量環境(這似乎是一種特定類型的詞法環境,從堆棧溢出時讀取其他線程,我發現在 ECMAScript 2016 中提到但未定義)。 變量環境具有使用 var 聲明的標識符以及與它們關聯的值。 詞法環境在其記錄的某處有綁定和用 let 和 const 聲明的變量的值。 但是,我有一些與此相關的問題。

變量環境只是詞法環境中的變量環境記錄(由於某種原因,記錄部分已經脫落)還是一個單獨的詞法環境具有外部詞法環境對某物的引用(外部變量環境或外部詞法環境)?

另外,閉包和作用域在這張圖片中的位置是什么? 據我了解,scope 只是當前執行上下文可訪問的內容,但它只是可訪問內容的想法還是 scope 的定義還包括 JavaScript 搜索環境變量和查找變量的方式以及scope鏈上的后續環境? 關於閉包,MDN 將閉包定義為“捆綁在一起(封閉)的 function 及其周圍 state(詞法環境)的組合”,我看到它在 ECMAScript 2016 中多次使用 - 閉包只是新的開始執行上下文,因為它們確定了詞法環境(變量環境呢)並且它們“包含” function?

最后,帶有 let 和 const 的變量在當前執行上下文中存儲在哪里? 我在一些 Stack Overflow 線程中看到它們位於詞法環境中(通過在 Google 中搜索我找不到任何東西) - 具體來說,這里的第一個答案( 全局 let 變量存儲在哪里? )說“因為你使用了 let它不是 var,而是存儲在與全局詞匯環境 object 關聯的聲明性環境記錄中,而不是存儲在全局 object 本身上。” 我認為總的來說是一樣的。 這種情況怎么辦:

function foo() {
    let a = 1;
    {
        let a = 2;
        console.log(a)
    }
    console.log(a)
}

foo()

這里發生了什么——名為“a”的兩個變量不能在同一個詞法環境中,對吧? 所以有兩個詞法環境,但是第二個是如何創建的。 是否在新塊的開頭創建了新的執行上下文? 是每個塊都會發生這種情況,還是只有那些用 let 和 const 聲明了新變量的塊?

抱歉所有問題,但我的主要問題是最后一個,我不明白理解它的基礎,這就是我問所有問題的原因。 感謝您的時間。

這里有幾個問題,真的。

MDN 將閉包定義為:

閉包是捆綁在一起(封閉)的 function 與對其周圍 state(詞匯環境)的引用的組合。 換句話說,閉包使您可以從內部 function 訪問外部函數的 scope。 在 JavaScript 中,每次創建 function 時都會在 function 創建時創建閉包。

希望這里的“換句話說”部分對“詞匯環境”的含義有所幫助。

相比之下, letconst的范圍是塊。 來自MDN

let 允許您聲明僅限於塊語句的 scope 或使用它的表達式的變量,這與 var 關鍵字不同,它在全局或本地定義一個變量到整個 function,而不管塊 Z31A1FD140BE4BEF2D18ZA21。 ...

所以基本上是一樣的,只是 scope 是塊級而不是函數級。

“全局詞法環境對象”和“全局對象”的區別

全局 object 基本上意味着全局變量作為屬性添加到window object。 請注意此示例中的差異(假設此代碼在全局 scope 中運行,而不是在函數中):

let t = 4;
console.log(t, window.t); // window.t will be undefined
// --> 4, undefined

var q = 4;
console.log(q, window.q); // window.q will equal the global q
// --> 4, 4

名為“a”的兩個變量不能在同一個詞法環境中?

*編輯:在做了更多閱讀之后,我發現我認為我對詞匯環境的了解並不是很准確。 查看ecma-262 規格,這似乎對這個主題有所了解:

一個詞法環境由一個環境記錄和一個可能的 null 對外部詞法環境的引用組成。 通常,詞法環境與 ECMAScript 代碼的某些特定句法結構相關聯,例如 FunctionDeclaration、BlockStatement 或 TryStatement 的 Catch 子句,並且每次評估此類代碼時都會創建一個新的詞法環境。

因此,您的示例中的塊似乎相對肯定正在獲得自己的詞法環境,具有指向 function 主體的外部詞法環境的引用/指針,依此類推。

ecma 規范中關於letconst的部分也做了一個有趣的區分:

變量是在實例化包含它們的詞法環境時創建的,但在評估變量的詞法綁定之前不能以任何方式訪問。

可變環境

在查看Execution Contexts 的規范部分時,它表明 Execution Context 包含一個名為 VariableEnvironment 的組件:

標識其 EnvironmentRecord 保存由此執行上下文中的 VariableStatements 創建的綁定的詞法環境。

所以這是第二個詞法環境,它有一個特定的目的。 為了弄清楚這個特殊目的是什么,讓我們看看環境記錄是什么:

聲明性環境記錄用於定義 ECMAScript 語言句法元素的效果,例如 FunctionDeclarations、VariableDeclarations 和 Catch 子句,它們直接將標識符綁定與 ECMAScript 語言值相關聯。 Object 環境記錄用於定義 ECMAScript 元素的效果,例如 WithStatement 將標識符綁定與某些 object 的屬性相關聯。

有幾件事似乎跳了出來。 它討論了catch子句和with語句。

  • Catch 子句似乎是一個奇怪的例外,在規范附件B.3.5 VariableStatements in Catch blocks中進行了討論。 這討論了對變量聲明行為的修改。
  • With 語句也是奇怪的鴨子,因為它們允許您引用 object 的屬性,就好像它們是局部變量一樣。

我在這里猜測了一下,但在我看來,執行上下文的這個VariableEnvironment屬性是第二個詞法環境,旨在處理類似於局部變量但實際上並非如此的奇怪事物。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM