var teacher = "Kyle";
function otherClass(){
var teacher = "Suzy";
console.log("Welcome!");
}
function ask(){
var question = "Why?";
console.log(question);
}
otherClass();
ask();
我們昨天提到:
- 第一次 parser 的階段, compiler 只在乎 Identifier。
- parser 完成就配對完成所有的 Scope, 此時
line 10
知道是 block Scope (綠色)。
- 所有的 lexically scoped language (像是 JavaScript),
決定所有的lexical scopes
andidentifiers
在compile time
,
而不是 run time 決定
。- 此時所有
var let const
之類的 Declaration 全部沒有意義,會移除,我們已經知道 Scope 規劃了。- run time 會使用我們決定好的 lexically scoped 並產生 bytecode,也就是大家熟悉的 interpreter JavaScript 。
line 1 : var teacher = "Kyle"
其實這邊有兩個 part :var teacher;
teacher = "Kyle";
有玩過 JAVASCRIPT AST VISUALIZER,
或是玩過 astexplorer ,
應該很可以體會:
compile time (AST)
產生astexplorer :
var teacher = "Kyle"
LHS、RHS 的 L、R 就是這邊的左右,但其實不是方向的「左」「右」。
是取決於有沒有 target。
書(scope & closures/ch1.md)上寫, 你要思考 :
事實上只有 LHS
,一般來說 LHS 表示有 target , retrieve source (value)
不是 LHS 的全部都是 RHS ,也就是說,不是 target 就是 source。
後面盡量用 receiveing
an assignment, target 的字眼來表示 LHS。
過於字面的文字沒有太多意義,理解比較重要。
舉例而言,
var teacher
的 teacher ,可以 接收值(receiveing an assignment)
,所以是 target positionconsole.log(question)
。 // 並沒有 target, 所以這是 soucre position。沒有 var 的 identifier
a.k.a. 小球 ,還要知道每一行是什麼 position
。遊戲裡面會有兩個角色:
scope manager 他知道目前 Scope 的規劃書(AST)。
Executing Code
line 1
。這時候,對 JavaScript engin 來說,已經沒有 var(let,const also),只知道是變數(variable)
。
JavaScript engin 看到 變數 teacher
是一個 target reference 。
JavaScript engin:「嘿!紅色木桶的 Scope manager, 我有一個 變數 是一個 target reference ,叫做
teacher
, 你有聽說過有一個叫做 teacher 的小球嗎?」
這邊的小球其實已經放入紅色桶子,所以當然 有
,
因為我們在 Run time 已經執行過一次對話了,那時候就制定小球和木桶的規劃。
Scope manager 這個階段基本上只回答 Yes or No。
紅色木桶的 Scope manager : 『Yes , 我知道它,拿去吧!』
這邊等同 JavaScript engin 在問 :
JavaScript engin :「嗨! 紅色木桶的 Scope manager ,你有看過一個小球叫做 teacher 嗎? 如果有,可以給我嗎?」
然後 JavaScript engin 根據拿到的 Scope(規劃書),就把值("Kyle")寫入 identifier (紅色小球)。
訊息 : 「 回傳 JavaScript engin 把值寫入 identifier。 」
line 3
。其實這邊看不到 line 3 ~ 12, 因為這些 code 是給上一個階段的規劃書(Scope)用的,他們都是 identifier 。
這個階段反而關注 Executable Code.
line 13
。這邊要思考之前說的問題: 知道每一行是什麼 position 。
所以 line 13 是什麼 position ?
target
of the assignment(LHS)source
of the assignment(RHS)Ans: source position.
我們沒有對 line 13 做任何賦值 (not assigning to it),
然後之前還提過 不是 target 就是 source。
所以我們要拿東西出來
。
JavaScript engin:「嘿!紅色木桶的 Scope manager, 我有一個 identifier 是一個 source reference ,叫做
otherClass
, 你有聽說過有一個叫做 otherClass 的小球嗎?」
紅色木桶的 Scope manager : 『Yes , 我知道它,拿去吧!』
這時候 JavaScript engin 拿出一堆放在記憶體的東西,這邊的例子是一個 function。
function otherClass(){
var teacher = "Suzy";
console.log("Welcome!");
}
訊息 : 「 回傳 JavaScript engin 一個 function , 而且是 藍色木桶裝的。 」
JavaScript engin 有時候可能拿到其他東西,比如 null, undefined,
如果拿到就會得到一個 TypeError
的錯誤。
不過這邊拿到 function ,沒有問題。
line 4
這邊還是需要思考之前說的問題: 知道每一行是什麼 position 。
所以 line 4 是什麼 position ?
Ans: 看到 assignment , retrieve value, 所以是 target position 。
JavaScript engin:「嘿! 藍色木桶的 Scope manager, 我有一個 變數 是一個 target reference ,叫做
teacher
, 你有聽說過有一個叫做 teacher 的小球嗎?」
這邊的小球其實已經放入藍色桶子
,所以當然 有
,
Scope manager 這個階段基本上只回答 Yes or No。
藍色木桶的 Scope manager : 『Yes , 我知道它,拿去吧!』
同樣的,這邊等同 JavaScript engin 在問 :
JavaScript engin :「嗨! 藍色桶子 的 Scope manager ,你有看過一個小球叫做 teacher 嗎? 如果有,可以給我嗎?」
然後 JavaScript engin 根據拿到的 Scope(規劃書),就把值("Suzy")寫入 identifier (藍色小球)。
訊息 : 「 回傳 JavaScript engin 把值寫入 identifier。 」
line 5
這邊補充說明一下,雖然不是我們宣告的,
但是這邊有一個東西叫做 console
,也是 identifier。
它被內建在 JavaScript 中 (Build-in)。
JAVASCRIPT AST VISUALIZER :
astexplorer:
所以 line 5 是什麼 position ?
不是 target,所以是 source position
所以我們要拿東西出來
。
JavaScript engin:「嘿!藍色木桶的 Scope manager, 我有一個 identifier 是一個 source reference ,叫做
console
, 你有聽說過有一個叫做 console 的小球嗎?」
藍色木桶的 Scope manager : 『No , 我沒看過它。』
沒看過的 identifier , Scope manager 會往外層尋找。
藍色木桶的 Scope manager : 『我幫你問看看 紅色木桶的 Scope manager 。』
紅色木桶的 Scope manager : 『Yes , 我知道它,拿去吧!』
因為 console 被內建在 JavaScript 中。
console 是一個 object , 有一個 method 叫做 log 。
這時候 JavaScript engin 拿出放在記憶體的 method 並執行它。
訊息 : 「 回傳 JavaScript engin 一個 object , 而且是 紅色木桶裝的。 」
是什麼 position
?line 14
JavaScript engin:「嘿!紅色木桶的 Scope manager, 我有一個 identifier 是一個 source reference ,叫做
ask
, 你有聽說過有一個叫做 ask 的小球嗎?」
紅色木桶的 Scope manager : 『Yes , 我知道它,拿去吧!』
訊息 : 「 回傳 JavaScript engin 一個 function , 而且是 綠色木桶裝的。 」
line 9
JavaScript engin:「嘿! 綠色木桶的 Scope manager, 我有一個 變數 是一個 target reference ,叫做
question
, 你有聽說過有一個叫做 question 的小球嗎?」
綠色木桶的 Scope manager : 『Yes , 我知道它,拿去吧!』
訊息 : 「 回傳 JavaScript engin 把值寫入 identifier。 」
line 10
JavaScript engin:「嘿!綠色木桶的 Scope manager, 我有一個 identifier 是一個 source reference ,叫做
console
, 你有聽說過有一個叫做 console 的小球嗎?」
綠色木桶的 Scope manager : 『No , 我沒看過它。』
綠色木桶的 Scope manager : 『我幫你問看看 紅色木桶的 Scope manager 。』
紅色木桶的 Scope manager : 『Yes , 我知道它,拿去吧!』
訊息 : 「 回傳 JavaScript engin 一個 object , 而且是 紅色木桶裝的。 」
問題來了,然後怎麼辦?
再問一次啊~
JavaScript engin:「嘿!綠色木桶的 Scope manager, 我有一個 identifier 是一個 source reference ,叫做
question
, 你有聽說過有一個叫做 question 的小球嗎?」
綠色木桶的 Scope manager : 『Yes , 我知道它,拿去吧!』
訊息 : 「 回傳 JavaScript engin 一個 值 , 而且是 綠色木桶裝的。 」
順帶一提,因為是 source reference ,所以拿出來的東西馬上就執行了。
看起來就會是 :ask() // "Why?"
把上面分散的對話一次完成,如果不確定可以拉上去看。
line 1
。JavaScript engin:「嘿!紅色木桶的 Scope manager, 我有一個 變數 是一個 target reference ,叫做
teacher
, 你有聽說過有一個叫做 teacher 的小球嗎?」
紅色木桶的 Scope manager : 『Yes , 我知道它,拿去吧!』
訊息 : 「 回傳 JavaScript engin 把值寫入 identifier。 」
line 3
。// Skip line 3 ~ 12
line 13
。JavaScript engin:「嘿!紅色木桶的 Scope manager, 我有一個 identifier 是一個 source reference ,叫做
otherClass
, 你有聽說過有一個叫做 otherClass 的小球嗎?」
訊息 : 「 回傳 JavaScript engin 一個 function , 而且是 藍色木桶裝的。 」
line 4
JavaScript engin:「嘿! 藍色木桶的 Scope manager, 我有一個 變數 是一個 target reference ,叫做
teacher
, 你有聽說過有一個叫做 teacher 的小球嗎?」
藍色木桶的 Scope manager : 『Yes , 我知道它,拿去吧!』
訊息 : 「 回傳 JavaScript engin 把值寫入 identifier。 」
line 5
JavaScript engin:「嘿!藍色木桶的 Scope manager, 我有一個 identifier 是一個 source reference ,叫做
console
, 你有聽說過有一個叫做 console 的小球嗎?」
藍色木桶的 Scope manager : 『No , 我沒看過它。』
藍色木桶的 Scope manager : 『我幫你問看看 紅色木桶的 Scope manager 。』
紅色木桶的 Scope manager : 『Yes , 我知道它,拿去吧!』
訊息 : 「 回傳 JavaScript engin 一個 object , 而且是 紅色木桶裝的。 」
line 14
JavaScript engin:「嘿!紅色木桶的 Scope manager, 我有一個 identifier 是一個 source reference ,叫做
ask
, 你有聽說過有一個叫做 ask 的小球嗎?」
紅色木桶的 Scope manager : 『Yes , 我知道它,拿去吧!』
訊息 : 「 回傳 JavaScript engin 一個 function , 而且是 綠色木桶裝的。 」
line 9
JavaScript engin:「嘿! 綠色木桶的 Scope manager, 我有一個 變數 是一個 target reference ,叫做
question
, 你有聽說過有一個叫做 question 的小球嗎?」
綠色木桶的 Scope manager : 『Yes , 我知道它,拿去吧!』
訊息 : 「 回傳 JavaScript engin 把值寫入 identifier。 」
JavaScript engin:「嘿!綠色木桶的 Scope manager, 我有一個 identifier 是一個 source reference ,叫做
console
, 你有聽說過有一個叫做 console 的小球嗎?」
綠色木桶的 Scope manager : 『No , 我沒看過它。』
綠色木桶的 Scope manager : 『我幫你問看看 紅色木桶的 Scope manager 。』
紅色木桶的 Scope manager : 『Yes , 我知道它,拿去吧!』
訊息 : 「 回傳 JavaScript engin 一個 object , 而且是 紅色木桶裝的。 」
line 10
JavaScript engin:「嘿!綠色木桶的 Scope manager, 我有一個 identifier 是一個 source reference ,叫做
question
, 你有聽說過有一個叫做 question 的小球嗎?」
綠色木桶的 Scope manager : 『Yes , 我知道它,拿去吧!』
訊息 : 「 回傳 JavaScript engin 一個 值 , 而且是 綠色木桶裝的。 」
// 全部結束。