2015年12月20日

[筆記] JavaScript中Scope Chain和outer environment的概念


在上一篇[筆記] 不同execution context的變項不會互相影響中,我們說明了不同的execution context所宣告的變項並不會互相影響,但如果我們不是宣告一個新的變項,而是直接引用一個變項的話,會怎麼樣呢?
讓我們來看看這個例子:


在function b()中,我們直接使用console.log來呼叫myVar這個變項,而沒有額外在function b中去宣告它,那麼這時候javaScript會呼叫出什麼樣的結果呢?會是1、2還是undefined呢?

答案是:1。


為什麼呢?

了解Outer Environment的概念


原因很簡單,在javaScript中,如果要呼叫一個在該exection context中沒有的變項時,它會往它的outer environment去找

因此雖然程式執行的過程中會先執行global execution context(myVar = 1),接著執行function a(myVar = 2),最後才執行function b。但是對於function b來說,它的outer environment就是最外層的global environment,所以找到的是var myVar = 1,而不是function a裡面的var myVar = 2。

圖片擷取至[Udemy]JavaScript: Understanding the weird parts

那麼,要怎麼區分誰是誰的outer environment呢?其實最簡單的方法就是直接從程式碼的相對位置來看,誰在誰的外面就可以了,也就是所謂的Lexical Environment (where something sits physically in the code you write):

我們可以把定義變項的地方畫一條直線(圖中淺黃色處),越往裡面就是越內層,
因此對於我們執行console.log的地方來說,它的外層(outer environment)就是var myVar = 1的地方,用這樣的方法,就可以判斷誰是誰的outer environment了!



再來談談Scope Chain


簡單的來說,Scope Chain就是在找變項的過程中,從內層找到外層,直到最外面的global environment的這條鍊,就叫做Scope Chain。按照上面的例子來說,就是先從function b()開始,在function b()裡面找myVar這個變項,可是找不到,因此便繼續往外層找,在最外層的global environment中,找到了myVar = 1。

讓我們把剛剛那個例子稍微做一下修改,把function b搬到function a裡面:


最後加以執行a()和b(),這時候我們會發現兩件事:

1. b()會得到 b is not defined的結果:之所以b會是not defined(記得是not defined不是undefined喔!),是因為這時候在最外層的global environment中,找不到function b。

2.這時候執行a()會得到2的結果:之所以會有這樣的結果,是因為當我們執行function a裡面的function b時,因為在function b裡面它找不到myVar這個變項,因此它開始往它的外層去搜尋,而這時候它的outer environment是function a,在function a裡面它便找到了myVar = 2,因此它就不再往outer environment (myVar = 1)去找了,直接回傳2這樣的結果。

我們同樣可以透過在程式碼中畫線的方式,來了解outer environment的關係,在function b裡面,我們執行console.log(myVar),因為在function b中找不到myVar,因此只好往外層去找,進而找到了function a裡面,在這裡面就找到了my Var = 2,因此就不會再繼續往外層的global environment去找。



而從b() --> a() --> global environment這樣的鍊,就稱作Scope Chain

圖片擷取至[Udemy]JavaScript: Understanding the weird parts

如果我們把function a裡面對於myVar的宣告拿掉的話,它才會繼續往外層搜尋myVar,直到找到global environment中有宣告myVar = 1這時候才會回傳1的結果。


如果我們更進一步的把global environment中,對於myVar的宣告也拿掉,那麼現在在global environment中也找不到myVar這個變項了,也就是說,在這整個Scope Chain中都找不到myVar,因此可想而知的,最後的結果是not defined。




→回到此系列文章目錄

資料來源


0 意見:

張貼留言