今天咱們來用介紹一下 JS 中的做用域鏈,先來看一段代碼:javascript
const name = "Lydia" const age = 21 const city = "San Francisco" function getPersonInfo() { const name = "Sarah" const age = 22 return `${name} is ${age} and lives in ${city}` } console.log(getPersonInfo())
上面調用了函數 getPersonInfo
,而後返回了一個包含 name
,age
,city
的字符串:java
Sarah is 22 and lives in San Francisco
。segmentfault
可是 getPersonInfo
這個函數中並無 city
變量,那麼它是怎麼訪問到 city
的呢?瀏覽器
首先,不一樣的執行上下文會分配不一樣的內存空間。咱們有默認的全局上下文(瀏覽器中是 window
,Node 中是 global
),函數 getPersonInfo
在被調用時也會建立一個 本地上下文。每一個執行上下文都有一個 做用域(鏈)。函數
對於函數 getPersonInfo
,它的做用域鏈就像下圖這樣:oop
做用域鏈基本上是對 對象(即上圖中的 activation object 和 global object)的 「引用鏈」,這些對象中包含了對該執行上下文中 可引用的變量及其餘做用域 的引用。而且,做用域鏈是在執行上下文被建立的時候建立的,即這一切發生在 運行時。spa
簡單來講,做用域(鏈)裏面存儲着執行上下文須要訪問的變量。翻譯
然而,本篇先不講 activation object 或者 執行上下文,咱們先把注意力放在 做用域(鏈) 上!
在下圖的例子中,執行上下文中的鍵值對即表明了做用域鏈對變量的引用。code
全局執行上下文中有三個變量:對象
本地執行上下文中有兩個變量:
當咱們在函數 getPersonInfo
中試圖訪問變量時,JS 引擎會首先檢查本地做用域鏈。
本地做用域鏈能夠訪問到 name
和 age
,它們的值分別是 Sarah
和 22
。可是當須要訪問 city
時會發生什麼呢?
爲了訪問 city
變量,JS 引擎會 順着做用域鏈查找。能夠說 JS 引擎是個耿直 boy,你提的要求他不會輕易放棄,他會沿着做用域鏈一直找 city
變量,直到找到頂層 global object
位置。
在全局做用域,因爲咱們定義了 city
的值爲 San Francisco
。因此函數拿到了這個值,而且打印出了 Sarah is 22 and lives in San Francisco
。
咱們說順着做用域鏈查找,可能說向上和向下都有歧義,那麼就統一更正爲向 外層 做用域查找好了!看下面的 3D 圖:
或者更多層的話:
咱們再來看最開始的例子:
上圖和最開始的例子幾乎是同樣的,只不過把 city
定義在了函數 getPersonInfo
中。咱們尚未調用函數 getPersonInfo
,因此本地做用域也沒有建立。那麼當咱們在全局做用域中訪問 name
、age
和 city
時:
程序拋出 ReferenceError
!由於在全局做用域中找不到變量 city
,而且已經沒有再外層的做用域了,即無法順着做用域鏈找下去。
除了全局做用域和本地做用域,還有一個是 塊級做用域,當咱們在花括號 { }
中用 let
或者 const
關鍵字定義變量時,就產生了塊級做用域。
const age = 21 function checkAge() { if (age < 21) { const message = "You cannot drink!" return message } else { const message = "You can drink!" return message } }
用虛線表示做用域以下:
咱們有一個全局做用域、一個函數做用域和兩個塊級做用域。也正是因爲塊級做用域的存在,因此咱們能定義 message
兩次。
咱們來回顧一下:
本篇就到這裏啦,本文是翻譯的系列文章:
本文首發於公衆號:碼力全開(codingonfire)
歡迎關注獲取最新內容哦~