iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 16
0
Modern Web

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

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

  • 分享至 

  • xImage
  •  

var teacher = "Kyle";

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

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

otherClass();
ask();

我們昨天提到:

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

Run time 會使用我們決定好的 lexically scoped

line 1 : var teacher = "Kyle"
其實這邊有兩個 part :var teacher; teacher = "Kyle";

有玩過 JAVASCRIPT AST VISUALIZER,
或是玩過 astexplorer ,

應該很可以體會:

  1. lexical scopes,identifiers 在 compile time (AST) 產生
  2. AST 沒有 值

astexplorer : var teacher = "Kyle"
astexplorer

再複習一個東西

LHS、RHS 的 L、R 就是這邊的左右,但其實不是方向的「左」「右」。
是取決於有沒有 target。

書(scope & closures/ch1.md)上寫, 你要思考 :

  • who's the target of the assignment(LHS)
  • who's the source of the assignment(RHS)

事實上只有 LHS ,一般來說 LHS 表示有 target , retrieve source (value)
不是 LHS 的全部都是 RHS ,也就是說,不是 target 就是 source。

後面盡量用 receiveing an assignment, target 的字眼來表示 LHS。
過於字面的文字沒有太多意義,理解比較重要。

舉例而言,

  • identifier var teacher 的 teacher ,可以 接收值(receiveing an assignment) ,所以是 target position
  • line 0 : console.log(question) 。 // 並沒有 target, 所以這是 soucre position。

Executing Code 時,就要組合 沒有 var 的 identifier a.k.a. 小球 ,還要知道每一行是什麼 position 。

遊戲裡面會有兩個角色:

  1. Scope manager

scope manager 他知道目前 Scope 的規劃書(AST)。

  1. JavaScript engin

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 ?

  • who’s the target of the assignment(LHS)
  • who’s the 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 ,沒有問題。

我們看到執行 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 , 而且是 紅色木桶裝的。 」

小總結

  1. 先找 是什麼 position ?
  • target position(LHS)
  • source position(RHS)
  1. 看 小球顏色 (identifier) 找木桶(Scope)。

我們回來 line 14

JavaScript engin:「嘿!紅色木桶的 Scope manager, 我有一個 identifier 是一個 source reference ,叫做 ask , 你有聽說過有一個叫做 ask 的小球嗎?」

紅色木桶的 Scope manager : 『Yes , 我知道它,拿去吧!』

訊息 : 「 回傳 JavaScript engin 一個 function , 而且是 綠色木桶裝的。 」

我們看到執行 function 的 line 9

JavaScript engin:「嘿! 綠色木桶的 Scope manager, 我有一個 變數 是一個 target reference ,叫做 question , 你有聽說過有一個叫做 question 的小球嗎?」

綠色木桶的 Scope manager : 『Yes , 我知道它,拿去吧!』

訊息 : 「 回傳 JavaScript engin 把值寫入 identifier。 」

我們看到執行 function 的 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 , 而且是 藍色木桶裝的。 」

我們看到執行 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 , 而且是 綠色木桶裝的。 」

我們看到執行 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 , 而且是 紅色木桶裝的。 」

我們看到執行 function 的 line 10

JavaScript engin:「嘿!綠色木桶的 Scope manager, 我有一個 identifier 是一個 source reference ,叫做 question , 你有聽說過有一個叫做 question 的小球嗎?」

綠色木桶的 Scope manager : 『Yes , 我知道它,拿去吧!』

訊息 : 「 回傳 JavaScript engin 一個 值 , 而且是 綠色木桶裝的。 」

// 全部結束。


上一篇
[day14] YDKJS (Scope) : 執行環境 (Execution Context)的角色扮演遊戲(compile time篇)
下一篇
[day16] YDKJS (Scope) : Lexical Scope Review(投影片當動畫),Error 種類
系列文
跟著 YDKJS 作者 Kyle Simpson 打造全新 JavaScript Mindset 共 31 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言