JavaScript 核心觀念(10)-執行環境與作用域-課後練習
前言
終於來到最後的課後練習,雖然課後練習中絕大部分問題都是我自己出的,但也是很值得回顧的練習,但是這邊會建議不要直接執行程式碼,而是透過觀察畫面來推敲結果答案。
第一題
1 | console.log(a); |
請問第一個 a 與 第二個 a 答案是什麼?
Hello
,undefined
undefined
,Hello
not defined
,Hello
Hello
,not defined
點我看解答(請認真思考後再看解答)
這一題主要考的是 Hoisting 觀念,創造階段變數會被提升,並賦予一個預設值,而這個預設值就是 undefined
,因此實際賦予值的階段是在執行階段,所以透過創造階段與執行階段的拆寫就會像這樣
創造階段
1 | var a; |
執行階段
1 | console.log(a); // undefined |
因此答案是 「2. undefined
, Hello
」
第二題
1 | 1 = true; |
請問以上程式碼會依序出現什麼錯誤訊息?
- LHS,
not defined
(RHS) not defined
(RHS), LHSundefined
, LHSnot defined
(RHS),undefined
點我看解答(請認真思考後再看解答)
這一題主要考的觀念是 Left-Head Side 以及 Right-Head Side
在 JavaScript 中我們無法針對原始型別賦予值,而原始型別有這些
- Boolean
- Null
- Undefined
- Number
- String
- BigInt
- Stmbol
因此 1 = true;
的 1 是一個 number 故無法賦予值就會出現 LHS 錯誤,而 console.log(a);
則是還未宣告所以無法呼叫所以會出現 RHS。
因此答案是 「1. LHS, not defined
(RHS)」。
你也可以試著玩看看以下程式碼是否可以運作?
1 | '' = true; |
但是原始型別中的 undefined 是一個奇妙的存在,因此當你輸入以下程式碼,你會發現都會回傳
1 | undefined = 1; |
基本上 JavaScript 允許你這麼做,所以不會出現 LHS 錯誤,但實際上千萬不要這麼幹,因為很蠢。
第三題
1 | function sayHi() { |
請問這個時候的 console
會出現什麼?
Hello Mary
Hello Tom
Hello Casper
- 以上皆非
點我看解答(請認真思考後再看解答)
這題答案是 「3. Hello Casper
」
這一題主要考的是語法作用域的觀念,在程式碼撰寫好時,就已經決定好了作用域,因此在 sayHi
中有重新宣告了 var a = 'Mary';
因此 a = 'Tom';
並不會影響到全域變數的 a
,所以答案才會是 Hello Casper
。
第四題
1 | function a() { |
請問當前 JavaScript 的執行順序狀況是如何以及執行堆疊結束時候順序又是如何?
- 執行順序:
a()
→c()
→b()
,執行堆疊結束順序:a()
→b()
→c()
- 執行順序:
a()
→c()
→b()
,執行堆疊結束順序:b()
→c()
→a()
- 執行順序:
c()
→b()
→a()
,執行堆疊結束順序:a()
→b()
→c()
- 執行順序:
b()
→a()
→c()
,執行堆疊結束順序:c()
→a()
→b()
點我看解答(請認真思考後再看解答)
這一題考的是執行堆與執行堆釋放,在這邊的觀念很簡單,執行堆的執行順序如何,那麼結束時就會反向回來,因此答案是 「2. 執行順序:a()
→ c()
→ b()
,執行堆疊結束順序:b()
→ c()
→ a()
」
第五題
1 | var name; |
請問過三秒後會出現什麼訊息呢?
- Hello Tomy
- Hello Casper
- Hello Mary
- Hello undefined
點我看解答(請認真思考後再看解答)
這一題的答案是「3. Hello Mary」
主要考的觀念一樣是語法作用域,因此傳入 name
函式的主要地方是 setTimeout
,因為 name
在執行 setTimeout
時,被賦予了 Mary
因此答案是 Hello Mary
第六題
1 | function fu() { |
請問 console 會是什麼?
- Hello
- oh!
- 以上皆非
點我看解答(請認真思考後再看解答)
這一題的答案是「2. oh!」
這個問題主要與提升有關係,在創造階段變數會被提升到最前面
1 | // 創造階段 |
接下來在執行階段時,因為 fu()
優先執行,而 var a
此時還沒有被賦予 true
而是預設值 undefined
,因此 if(a)
會是 false
(undefined
= false
),所以才會出現 oh!。
1 | // 執行階段 |
第七題
1 | function fu() { |
請問實際程式運作的樣子是什麼(拆解)?
第一種拆解
1 | // 創造階段 |
第二種拆解
1 | // 創造階段 |
第三種拆解
1 | // 創造階段 |
第四種拆解
1 | // 創造階段 |
點我看解答(請認真思考後再看解答)
答案是「第一種拆解」
這一題主要考的是提升觀念,而最主要的重點在於函式比變數有更高的優先權,並且 undefined
會被型轉為 false
。
第八題
1 | function youName() { |
請問這個答案會是什麼?
- 你叫什麼? → 我叫 Tomy! → oh! Tomy 你好
- 你叫什麼? → oh! Tomy 你好! → 我叫 Tomy!
點我看解答(請認真思考後再看解答)
這一題答案是「2. 你叫什麼? → oh! Tomy 你好! → 我叫 Tomy!」
主要考的觀念是非同步觀念,由於 myName
裡面是一個 setTimeout
因此會被放進事件貯列,等後其他動作執行完才會回來看這個事件,因此順序才會是「你叫什麼? → oh! Tomy 你好! → 我叫 Tomy!」
第九題
1 | function sayHi(name) { |
請問這樣出現什麼訊息呢?
- Tomy 你好
- 不會執行 sayHi()
- LHS
- undefined 你好
點我看解答(請認真思考後再看解答)
這一題答案是「3. LHS」
這一題主要考的觀念是 Left-Head Side 以及 Right-Head Side
雖然在前面有講過如何原始型別中的 undefined 無法被賦予值之外,function 的名稱也無法被賦予值。
第十題
1 | function sayHi (a){ |
請問當 sayHi() 執行後會出現什麼訊息?
- Mary
- Mark
- Casper
- HexSchool
點我看解答(請認真思考後再看解答)
這一題答案是「1. Mary」
這一題主要重點觀念在於「當函式裡面重新宣告一個變數,就不會影響到外部變數」,因為這個 var a
是屬於函式裡面的變數,當函式執行完畢後,因為並沒有回傳變數給予接收,所以記憶體就被釋放了,故答案才會是 Mary,因此這邊另一個重點觀念在於「記憶體釋放」。
所以說 a='HexSchool'
這個 a
是存活在 sayHi
裡面的變數,因此並不會向外尋找另一個 a