91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

JavaScript中Hoisting詳解 (變量提升與函數聲明提升)

發布時間:2020-09-28 20:43:33 來源:腳本之家 閱讀:235 作者:daisy 欄目:web開發

本文主要給大家介紹了關于JavaScript中Hoisting(變量提升與函數聲明提升)的相關內容,分享出來供大家參考學習,下面話不多說了,來一起看看詳細的介紹吧。

如何將 函數聲明 / 變量 “移動” 到作用域的頂部。

術語 Hoisting(提升) 在很多 JavaScript 博文中被用來解釋標識符的解析。其實 Hoisting(提升) 這個詞是用來解釋 變量 和 函數聲明 是如何被提升到 函數或全局 作用域頂部的。你在任何的 JavaScript 文檔中找不到這個術語,我們說的 Hoisting(提升) 只是使用了其字面含義來做個比喻。

如果你已經對 JavaScript 作用域工作原理有基本的了解,那么更深入的了解 Hoisting(提升) 有助于你建立更強大的基礎知識。(愚人碼頭注:作為 JavaScript 中的一個總要概念,變量提升和函數聲明提升經常在前端開發面試時被問及,或者在前端開發筆試題中出現。可見了解 Hoisting(提升) 的重要性。)

為了更好地理解基礎知識,讓我們來回顧一下 “Hoisting(提升)” 到底意味著什么。另外,給你一個提醒,JavaScript 是一種解釋性語言,這不同于編譯性語言,這意味著JS代碼是逐行執行的。

請考慮以下示例:

console.log(notyetdeclared);
// 打印 'undefined'
 
var notyetdeclared = 'now it is declared';
 
hoisting();
 
function hoisting(){
 console.log(notyetdeclared);
 // 打印 'undefined'
 
 var notyetdeclared = 'declared differently';
 
 console.log(notyetdeclared);
 // 打印 'declared differently'
}

在分析上面的示例代碼之后,提出幾個問題:

  • 第 6 行,該函數聲明之前為何能訪問?
  • 第 1 行,沒有拋出錯誤,是因為這時變量 notyetdeclared 不存在嗎?
  • 第 4 行,notyetdeclared 已經在全局作用域內聲明了,為什么在第 9 行打印時還是  undefined 呢?

JavaScript 是非常合乎邏輯的,所有這些奇怪問題都有一個明確的解釋。

我們從頂部開始解釋,當代碼在 JavaScript 中執行時,就會建立一個執行期上下文。 JavaScript 中有兩種主要的執行期上下文類型 – 全局執行期上下文和函數執行期上下文(愚人碼頭注:特別注意,執行期上下文和我們平常說的上下文不同,執行期上下文指的是作用域,而平常說的上下文是 this 的取值指向)。由于 JavaScript 是基于單線程執行模型,所以每次只能執行一段代碼。

對于我們上面的代碼,這個過程如圖所示:

JavaScript中Hoisting詳解 (變量提升與函數聲明提升)

上述示例代碼的調用棧:

  • 程序從棧(stack)上的全局執行期上下文開始執行。
  • 當調用 hoisting() 函數時,將一個新的函數執行期上下文推到棧(stack)上,并且全局執行期上下文被暫停。
  • 在 hoisting() 執行完成后 , hoisting()執行期上下文從棧(stack)中彈出,全局執行期上下文恢復。

這個過程是自解釋的,但并沒有真正解釋我們在執行示例代碼時所看到的異常。當執行期上下文跟蹤代碼的執行情況時,詞法環境跟蹤標識符到特定變量的映射。詞法環境基本上是 JavaScript 作用域機制的內部實現。通常,詞法環境與 JavaScript 代碼的特定結構相關聯,例如一個函數或一個 for 循環代碼塊。每當創建一個函數時,對其創建的詞法環境的引用將在一個名為 [[Environment]] 的內部屬性中傳遞。

所有這些術語涵蓋的是一個簡單而非常合乎邏輯的概念。允許將其分解。詞法環境是一個有趣的名稱,用于跟蹤代碼塊中的變量和函數。除了跟蹤局部變量、函數聲明和參數之外,每個詞法環境還跟蹤其父級詞法環境。所以上面的示例代碼在 JavaScript 引擎中會被這樣解析。上述代碼的詞法環境,如圖所示:

JavaScript中Hoisting詳解 (變量提升與函數聲明提升)

注:

如果理解起來有問題,請查看以下三篇文章:

  • 深入理解JavaScript中的作用域和上下文
  • JavaScript 核心概念之作用域和閉包
  • 實例分析 JavaScript 作用域

為了在詞法環境中解析標識符, JavaScript 引擎將檢查當前環境的引用。如果沒有找到引用,則通過使用 [[environment]] 移動到外部環境。這將一直持續進行下去,直到標識符被找到,或者拋出一個 ‘not defined'(未定義) 的錯誤。

基本上,JavaScript 代碼的執行分為兩個階段。第一個階段在當前詞法環境中注冊所有的變量和函數聲明。完成之后,第二個階段的 JavaScript 執行就開始了!

所以要詳細說明第一階段:它在兩個步驟中起作用。

  • 掃描當前函數聲明中的代碼。函數表達式和箭頭函數會被跳過。對于每個被發現的函數,都會創建一個新的函數,并使用函數名稱將其綁定到環境中。如果標識符的名稱已經存在,那么它的值就會被覆蓋。
  • 然后掃描當前環境的變量。找到使用 var 定義的變量和放置在其他函數之外的變量,并注冊一個標識符,其值初始化為 undefined 。如果存在標識符,則該值將保持不變。

注意:用 let 和 const 定義的是塊變量,與 var 的處理稍微不同。在另一篇文章中了解更多的內容。

現在你應該已經對詞法環境這個基本概念有了一定的了解,那么讓我們回到示例代碼中,并解釋這些問題。

在設置全局上下文時,將對環境進行掃描,并將 hoisting() 函數附加到標識符上。然后在下一步中,變量 notyetdeclared 被注冊,其值初始化為 undefined 。按照這個步驟繼續理解代碼。

現在我們來解釋示例代碼中提出的3個問題:

第 6 行,該函數聲明之前為何能訪問?

第1階段, hoisting() 函數已經注冊到了標識符中,當JS代碼在第2階段的全局執行期上下文中開始執行時,它會查找 hoisting 的詞法環境,并在其定義之前找到該函數。

第 1 行,沒有拋出錯誤,是因為這時變量 notyetdeclared 不存在嗎?

同樣的,notyetdeclared 被注冊到了標識符,并在第1階段中初始化為 undefined ,因此不會拋出任何錯誤。

最后,

第 4 行,notyetdeclared 已經在全局作用域內聲明了,為什么在第 9 行打印時還是 undefined 呢?

現在我們進入函數 hoisting 環境中。在第1階段中,notyetdeclared 被注冊并初始化為  undefined,因為在這個詞法環境中,notyetdeclared 的變量還沒有被注冊。如果第 12 行不包含var 關鍵字,那么情況就不同了。

希望現在可以清楚地看到,在 JavaScript 中 Hoisting(提升) 只是我們用于解釋其背后原理的一個觀點,從技術上來講,函數和變量并不會移動到任何地方。

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

额济纳旗| 金川县| 法库县| 防城港市| 裕民县| 喜德县| 濮阳市| 长治县| 余庆县| 嵊州市| 轮台县| 定襄县| 濮阳县| 古浪县| 盐山县| 郓城县| 汕尾市| 维西| 大城县| 东至县| 江口县| 射洪县| 石泉县| 高安市| 崇仁县| 镇江市| 喀喇沁旗| 阿拉善左旗| 垫江县| 咸丰县| 方正县| 台中市| 黄平县| 长宁区| 曲麻莱县| 老河口市| 溧阳市| 潼南县| 甘孜| 大悟县| 泾阳县|