iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 15
1
Modern Web

跟著 YDKJS 作者 Kyle Simpson 打造全新 JavaScript Mindset系列 第 15

[day14] YDKJS (Scope) : 執行環境 (Execution Context)的角色扮演遊戲(compile time篇)

  • 分享至 

  • xImage
  •  

陪陪 JavaScript 玩 丟球遊戲 , 好嗎?

這個是今天的範例,估計會一直看到它

var teacher = "Kyle";

function otherClass(){
	var teacher = "Suzy";
  	console.log("Welcome!");
}

function ask(){
  var question = "Why?";
  console.log(question);
}

otherClass();
ask();

遊戲裡面會有兩個角色:

  1. Scope manager

scope manager 製造 有顏色的桶子(buckets),有顏色的小球 (marbles)。
然後 compiler 會問要怎麼丟球分配。

  1. compiler

( processing the JavaScript program.)

這兩個角色溝通完,會產生一個計畫 (plan)。
真正執行產生 bytecode 的時候,會依照這份計畫執行。

前置道具:
紅色:global
藍色:不是 global 的 block 顏色
綠色:反正 block 顏色不能重複
... 其他顏色 ,etc.

identifier 就是我們的小球
Scope 就是我們的桶子

昨天提過 Declaration,可以確認:
JavaScript ast 產生器
[day13] YDKJS (Scope) : JavaScript 是 parser language ? 不是 interpreter 嗎?


首先,我們看到 line 1

這時候,因為是第一次 parsed(為了 AST 產生),會有一個 Scope manager 創造一個 紅色桶子。

訊息:「Scope manager 已經創造一個 紅色桶子。」

compiler 看到 var teacher 是一個 Variable Declaration。

compiler:「嘿!紅色桶子 的 manager, 你有聽說過有一個東西(Identifier)叫做 teacher 嗎?」

compiler 問 紅色桶子的 manager 有沒有一個 Identifier 叫做 teacher

紅色桶子 的 manager 看一下,此時還沒有出現這個東西 。
所以 紅色桶子 的 manager 會這樣回覆 :

紅色桶子 的 manager : 『我沒有聽過耶。我這邊有一個紅色桶子!把那個紅色小球丟進來吧!』

然後我們把這個小球丟進去 紅色桶子。

這時候做的事情是「規劃 執行環境 (Execution Context)」。

  1. 紅色則代表 Global Execution Context。
  2. 紅色桶子 就是 Global Scope。
  3. 小球丟進紅色 就是 Identifier 是 Global Scope 。

我們看到 line 3

compiler 看到 function otherClass() 是一個 function Declaration。

compiler 又會問:有這個東西存在嗎?

compiler:「嘿!紅色桶子 的 manager, 你有聽說過有一個東西(Identifier)叫做 otherClass 嗎?」

紅色桶子 的 manager : 『我沒有聽過耶。』
紅色桶子 的 manager : 『我這邊有一個紅色桶子!把那個紅色小球(Identifier)丟進來吧!』

這時候 compiler 才會知道整個 function otherClass() 是一個 紅色桶子。

紅色桶子正在裝 function otherClass()

可是又遇到一個 { .. } 的 block ,
這時候,裡面就要用其他顏色的桶子裝小球(Identifier),
因為 function 裡面是一個 block,所以要換桶子(Scope)。

可以參考,書(scope & closures/ch2.md)上這張圖的感覺(橘色的 2 就是我們說的藍色桶子):

這時候,有一個 Scope manager 創造一個 藍色桶子。

訊息:「Scope manager 已經創造一個 藍色桶子。」

補充: 昨天有請大家先看書。
Contextual Rules 的 { .. } Curly Braces。

我們看到 line 4

compiler 在藍色桶子 看到 var teacher 是一個 Variable Declaration。

compiler:「嘿!藍色桶子 的 manager, 你有聽說過有一個東西(Identifier)叫做 teacher 嗎?」

因為不同顏色桶子的 manager 不一樣,所以 藍色桶子 的 manager 還沒有看過。

藍色桶子 的 manager : 『我沒有聽過耶。』
藍色桶子 的 manager : 『我這邊有一個藍色桶子!把那個藍色小球(Identifier)丟進來吧!』

雖然名稱一樣,但是不同桶子的 manager 是不同人,所以不認識。

  • 這種出現很多 Identifier 名稱一樣,但是Scope 不一樣的狀況,或是 同名 Identifier 又稱作 shadowing
    如果存在 shadowing ,那 Identifier 的存取只能在同一個 Scope。

    也就是藍色的 Scope manager 不會知道外面還有一個 紅色的 同名 小球(global shadowing identifier)

小小總結:

  1. 藍色則代表 function Execution Context。
  2. 藍色桶子 就是 function Scope。
  3. 小球丟進藍色 就是 Identifier 是 function Scope 。

我們看到 line 5

line 5 不是一個 Declaration,所以跳過。

而且因為藍色桶子內都執行過了,所以 compiler 離開藍色桶子。

我們看到 line 8

此時,compiler 已經離開藍色桶子,回到紅色桶子的區域。

compiler 看到 function ask() 是一個 function Declaration。

compiler:「嘿!紅色桶子 的 manager, 你有聽說過有一個東西(Identifier)叫做 ask 嗎?」

紅色桶子 的 manager : 『我沒有聽過耶。』
紅色桶子 的 manager : 『我這邊有一個紅色桶子!把那個紅色小球(Identifier)丟進來吧!』

這時候 compiler 才知道整個 function ask() 是一個 紅色桶子。

紅色桶子正在裝 function ask()

可是又遇到一個 { .. } 的 block ,
這時候,裡面就要用其他顏色的桶子裝小球(Identifier),
因為 function 裡面是一個 block,所以要換桶子(Scope)。

這時候,有一個 Scope manager 創造一個桶子,可是藍色已經分配出去了,所以這邊改用綠色。

可以參考,書(scope & closures/ch2.md)上這張圖的感覺(橘色的 2 就是我們說的綠色桶子):

訊息:「Scope manager 已經創造一個 綠色桶子。」

我們看到 line 9

compiler 在 綠色桶子 看到 var question 是一個 Variable Declaration。

compiler:「嘿!綠色桶子 的 manager, 你有聽說過有一個東西(Identifier)叫做 question 嗎?」

因為不同顏色桶子的 manager 不一樣,所以 綠色桶子 的 manager 還沒有看過。

綠色桶子 的 manager : 『我沒有聽過耶。』
綠色桶子 的 manager : 『我這邊有一個綠色桶子!把那個綠色小球(Identifier)丟進來吧!』

小小總結:

  1. 綠色則代表另一個 function Execution Context。
  2. 綠色桶子另一個 就是 function Scope。
  3. 小球丟進綠色 就是 Identifier 是另一個 function Scope 。

總結

把上面分散的對話一次完成,如果不確定可以拉上去看。

首先,我們看到 line 1

訊息:「Scope manager 已經創造一個 紅色桶子。」

compiler:「嘿!紅色桶子 的 manager, 你有聽說過有一個東西(Identifier)叫做 teacher 嗎?」

紅色桶子 的 manager : 『我沒有聽過耶。我這邊有一個紅色桶子!把那個紅色小球丟進來吧!』

我們看到 line 3

compiler:「嘿!紅色桶子 的 manager, 你有聽說過有一個東西(Identifier)叫做 otherClass 嗎?」

紅色桶子 的 manager : 『我沒有聽過耶。』
紅色桶子 的 manager : 『我這邊有一個紅色桶子!把那個紅色小球(Identifier)丟進來吧!』

因為 function 裡面是一個 block,所以要換桶子(Scope)。

訊息:「Scope manager 已經創造一個 藍色桶子。」

我們看到 line 4

compiler:「嘿!藍色桶子 的 manager, 你有聽說過有一個東西(Identifier)叫做 teacher 嗎?」

因為不同顏色桶子的 manager 不一樣,所以 藍色桶子 的 manager 還沒有看過。

藍色桶子 的 manager : 『我沒有聽過耶。』
藍色桶子 的 manager : 『我這邊有一個藍色桶子!把那個藍色小球(Identifier)丟進來吧!』

我們看到 line 5

line 5 不是一個 Declaration,所以跳過。
而且因為藍色桶子內都執行過了,所以 compiler 離開藍色桶子。

我們看到 line 8

此時,compiler 已經離開藍色桶子,回到紅色桶子的區域。

compiler:「嘿!紅色桶子 的 manager, 你有聽說過有一個東西(Identifier)叫做 ask 嗎?」

紅色桶子 的 manager : 『我沒有聽過耶。』
紅色桶子 的 manager : 『我這邊有一個紅色桶子!把那個紅色小球(Identifier)丟進來吧!』

因為 function 裡面是一個 block,所以要換桶子(Scope)。
這時候,有一個 Scope manager 創造一個桶子,可是藍色已經分配出去了,所以這邊改用綠色。

訊息:「Scope manager 已經創造一個 綠色桶子。」

我們看到 line 9

compiler:「嘿!綠色桶子 的 manager, 你有聽說過有一個東西(Identifier)叫做 question 嗎?」

因為不同顏色桶子的 manager 不一樣,所以 綠色桶子 的 manager 還沒有看過。

綠色桶子 的 manager : 『我沒有聽過耶。』
綠色桶子 的 manager : 『我這邊有一個綠色桶子!把那個綠色小球(Identifier)丟進來吧!』

沒有其他 Identifier ,第一次 parser 結束

技術總結

  1. 這個第一次 parser 的階段, compiler 只在乎 Identifier。
  2. parser 完成就配對完成所有的 Scope, 此時 line 10 知道是 block Scope (綠色)。
  3. 所有的 lexically scoped language (像是 JavaScript),
    決定所有的 lexical scopes and identifierscompile time
    不是 run time 決定
  4. 此時所有 var let const 之類的 Declaration 全部沒有意義,會移除,我們已經知道 Scope 規劃了。
  5. run time 會使用我們決定好的 lexically scoped 並產生 bytecode,也就是大家熟悉的 interpreter JavaScript 。

Run Time 下集待續 :P


上一篇
[day13] YDKJS (Scope) : JavaScript 是 parser language ? 不是 interpreter 嗎?
下一篇
[day15] YDKJS (Scope) : 執行環境(Execution Context)的角色扮演遊戲(Executing time篇 )
系列文
跟著 YDKJS 作者 Kyle Simpson 打造全新 JavaScript Mindset31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言