iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 18
0
Modern Web

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

[day17] YDKJS (Scope) : 不要耍白目 JavaScript! (Dynamic Global Variable, Strict Mode)

[day16] YDKJS (Scope) : Lexical Scope Review 有投影片輔助理解,今天就不以對話的形式呈現全部了。

compile time

line 1, line3 都沒問題,分別是 Variable Declaration, Function Declaration。

我們把 code 丟進去 AST VISUALIZER:

var teacher = "Kyle";

function otherClass(){
	teacher = "Suzy";
  topic = "React";
  console.log("welcome!");
}

otherClass();

teacher;
topic;

JAVASCRIPT AST VISUALIZER

line 4, line 5 得到 Expression Statement

代表 compile time 還不會執行。

compile time 執行 Declaration

也就是說,雖然line 3 有產生新的 local lexical scope (新的藍色木桶),
但是裡面沒有 Declaration,所以沒有藍色小球 (local lexical scope 的 identifier)。

離開 local lexical scope,global scope 也沒有其他 Declaration, compile time 在這邊就全部結束。

Executing time

line 1 : 沒有問題,和之前例子一樣(target reference)。

line 4 : JavaScript 往上層找 global identifier

對話像是:

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

藍色木桶的 Scope manager : 『No , 我沒看過它。我幫你問看看 紅色木桶的 Scope manager 。』

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

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

註:之前有提過,同名 Identifier,這也算是 shadowing 其中一種。

Dynamic Global Variable

那麼,line 5 ?

  • 之前有說,Executing time 沒有 var, let, const 的 Declaration(忘記可以回去複習)。
  • 所以 line 4, line 5 是 target reference。

上面兩則,問題不大,
但問題是 local lexical scope (藍色木桶) 沒有我們要的 藍色小球 (local lexical scope 的 identifier)。

  • 我們往上找(global scope, 有張建築物的比喻可以回去複習)。
  • 外層也沒有,所以 執行到(line5) topic 會有 Error ?

你這樣想,代表你沒有太大錯誤,有錯的是 JavaScript 自己認為自己很聰明

JavaScript 自己認為自己很聰明 要符合幾個條件:

  • 前提是,你是 target reference 。

  • 找到上層 global scope 都 沒有找到 identifier 。

  • JavaScript 會在 Executing time 動態產生一個 global identifier ,讓你不出錯。

  • 後來大多數人覺得 JavaScript 很白目,所以另外做一個模式防止這個自做聰明的白目行為(稍後講),所以你不能是這個 防止白目行為 的模式。

對話像是這樣:

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

藍色木桶的 Scope manager : 『No , 我沒看過它。我幫你問看看 紅色木桶的 Scope manager 。』

紅色木桶的 Scope manager : 『No , 我沒看過它。』
紅色木桶的 Scope manager :『不過你都辛苦找到我這邊了,怕你出現錯誤,我直接幫你動態產生,我真貼心~』
紅色木桶的 Scope manager :『拿去吧!』

// programmer(你) : ???

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

// programmer(你) : 不要耍白目 JavaScript!


所以,最後 line 11 結果:

teacher 是一個 source reference。
紅色木桶的 Scope manager : 『Yes , 我知道它,拿去吧!』

teacher; // "Suzy"

最後 line 12 結果:

topic 是一個 source reference。
紅色木桶的 Scope manager : 『Yes , 我知道它,拿去吧!』

topic; // "React"
// programmer(你): (無言)

補充

如果 line 11 改到 line 8,
也就是 otherClass() function 不會執行,

那麼 teacher; // "Kyle"
因為Executing time 的 JavaScript 是由上到下一行一行直譯式的。

Strict Mode

你第一行使用 "use strict" 才會開啟這個模式。

差別是你執行到 line 7

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

藍色木桶的 Scope manager : 『No , 我沒看過它。我幫你問看看 紅色木桶的 Scope manager 。』

紅色木桶的 Scope manager : 『No , 我沒看過它。』

訊息 : 「 Reference Error. 」

註: Error [day16] YDKJS (Scope) : Lexical Scope Review
有提到。

  • 沒有找到 variable : ReferenceError
  • 有找到 variable : TypeError

你要自己使用 "use strict" 才會開啟這個模式,
JavaScript 預設沒有開啟,所以大家才會建議你無論如何都要開啟這個模式。

不過如果你有用 transpilers 像是 Babel,則編譯出來的 code 都會有這個模式。

另外一個無關痛癢的細節
the Spec. 有提到 Class、ES6 module 內部是預設 strict mode

  • Module code is always strict mode code.
  • ClassDeclaration、ClassExpression are strict mode .

上一篇
[day16] YDKJS (Scope) : Lexical Scope Review(投影片當動畫),Error 種類
下一篇
[day18] YDKJS (Scope) : Nested scope
系列文
跟著 YDKJS 作者 Kyle Simpson 打造全新 JavaScript Mindset31

尚未有邦友留言

立即登入留言