(Day02) 範圍鍊與提升
範圍鍊 (Scope Chain)
範圍鍊在 JavaScript 一堆奇奇怪怪的觀念中算是簡單好懂的,簡單來說就是:
『函示內沒有對應的變數、常數或是函示時,他會往外層尋找』
這邊一樣用程式碼來說明。
1 | function playGame(){ |
上面這段 gaming
在函示內,因此能正確顯示,這段好像廢話,不過接下來我們試者把 gaming
移到外層全域看看結果如何:
1 | const gaming = 'PS5' |
結果是一樣的,上面 playGame()
函式中因為本身沒有 gaming
常數,因此他會到外層也是全域 (window) ,來獲得 gaming
常數的資料。
接下來便是在函示內外都新增兩個 gaming
來看看結果如何
1 | const gaming = 'PS5' |
所以結果就是當函示內有相關資料時,變不會往外層尋找,而是直接使用函示內資料。
提升(Hoisting)
(因為 const
、 let
提升的狀況不一樣,這邊範例先改為使用 var
, const
、 let
會到介紹他們的章節再來提及)
JavaScript 實際編譯並執行程式碼時,會分為兩種階段:
- 創造階段
- 執行階段
等創造階段執行完畢,才會進入執行階段,創造階段有幾個重點:
- 優先建立函示(執行環境) 但不運行,只是建立環境。
- 再來建立變數,但不會為變數賦值,只是建立一個空值 (undefined) 的變數。
- 用言語形容這個階段的話就是一個先建立容器,因為這個創造階段的特性,所以這個狀況被稱做 Hoisting (提升)。
而執行階段的重點則是:
- 執行 呼叫函式 的
XX()
。 - 為變數賦予實際的值。
這邊使用上面程式碼,並稍微調一下順序就可驗證上面提到的創造階段。
1 | console.log(gaming) // undefined |
console.log(gaming)
這段會因為變數被提升,但尚未賦值因此是 cosnole 會回傳 undefined
playGame()
則是 function playGame()
函示會因為提升效果,而先比被呼叫函示的 playGame()
建立,因此 console 可以正確顯示。
因為提升這個 特性 會讓上面的程式碼,在編譯順序變為:
1 | // 創造階段 |
最後要說的是,Hoisting 只是概念,只是幫助我們理解,程式碼在編譯時會這麼做,但他仍只是一種概念, 這點 MDN 文件也有說明到:
提升(Hoisting)是在 ECMAScript® 2015 Language Specification 裡面找不到的專有名詞。它是一種釐清 JaveScript 在執行階段內文如何運行的思路(尤其是在創建和執行階段)。
參考文獻
- JavaScript 核心篇 (六角學院)
- JavaScript 核心觀念(6)-執行環境與作用域-提升
- MDN 文件(提升)