JavaScript 的 var、let 與 const

2022/6/14

JavaScript 因為歷史悠久, 所以你可能會遇到經過多人更改過的 JavaScript 程式, 裡面混雜了不同時期 JavaScript 的語法, 導致有時候 JavaScript 程式就是難懂, 本文將針對宣告變數的幾種方法加以說明, 期望能讓大家快速理解其中的差別。

使用 var 宣告函式層級的變數

過去最常看到的變數宣告方是就是使用 var, 它宣告的變數是函式層級, 也就是只要離開宣告時所在的函式, 這個變數就失效了

全域變數

如果在函式外使用 var 宣告變數, 它就會變成全域變數, 在程式內任何地方都可以取用

宣告與設定初值分離

你也可以把宣告和設定初值分開來, 不一定要同時完成

重複宣告

你也可以重複宣告同一個變數, 只要沒有設定新的值, 就會保留原值

變數提升 (variable hoisting)

變數有一個我其實不知道有什麼用途, 但是很多人喜歡拿來考別人的功能, 叫做 變數提升 (variable hoisting), 會把宣告變數的動作提升到執行其他程式前先完成, 意思就是在進入變數的有效範圍內時, 會在執行第一行程式前就先宣告變數。因此, 在執行第一行程式的時候, 變數就已經存在了。

全域變數會成為全域物件的屬性

以 var 宣告的全域變數會成為全域物件的屬性,不過這個屬性是不可設定 (non-configurable) 的, 也就是不能使用 delete 移除

使用 let 宣告區塊層級的變數

所謂的區塊, 就是由一對大括號括起來的區域, 使用 let 宣告的變數只要出了所在的區塊, 就會失效

分辨區塊

在大部分的情況下, 我們很容易辨識區塊, 不過在像是 for 的敘述中, 初始設定也是區塊的一部份, 因此在初始設定內宣告的變數在 for 結束後也一樣會失效

全域變數

在任何區塊外使用 let 建立的變數一樣是全域變數, 可在程式中任何地方取用

不能重複宣告變數

變數提升不會設定初值

以 let 宣告變數也一樣具有變數提升功能, 但是並不會設定初值, 在使用變數前一定要先透過 let 宣告

以 let 宣告的變數不會成為全域物件的屬性

以 let 宣告的變數並不會像是以 var 宣告的變數那樣成為全域物件的屬性

使用 const 宣告不能變更的變數

你也可以使用 const 宣告變數, 不過這種變數如同 const 字面所示, 是不能變的, 中文翻譯為常數

宣告常數時一定要設定值

以 const 宣告常數時必須一併設定初值, 不能將宣告與設定初值分開進行

變更常數所參照的物件

請特別注意, 不能變更以 const 宣告的常數指的是不能重新設定常數本身, 如果常數的內容是一個物件, 你還是可以變更物件內的屬性

沒有宣告直接設定變數

JavaScript 是很寬鬆的, 你甚至會看到有些程式中根本沒有宣告就直接設定變數的值

未宣告的變數其實是全域物件的屬性

之所以會有前述範例的結果, 是因為當 JavaScript 看到識別字時, 會一層層的往外找尋是否有符合該名稱的宣告,如果在全域變數裡也找不到, 就會往全域物件 globalThis 找它的屬性, 這也是為什麼你可以直接以 alert 叫用定義在 globalThis 物件內的 alert

你可以在任何地方用這種方式幫全域物件增加屬性, 並且以像是全域變數的方式使用該屬性。也就是說, 若不使用 varletconst 宣告而直接設定值, 並不會建立變數, 而是設定全域物件 globalThis 的屬性。這樣的作法看起來好像很方便, 隨時想用就用, 但是卻容易造成混淆, 搞不清楚到底是在哪裡設定初值, 若要避免這個問題, 可以強制使用嚴格模式

var 全域變數與純全域物件屬性的差異

你可能會想到, 前面不是有提到以 var 宣告的全域變數也會變成全域物件的屬性, 這樣和剛剛提到單純全域物件的屬性不是一樣嗎?還記得前面說明過, 以 var 宣告的全域變數會成為全域物件中不可設定的屬性, 具體的表現就是你無法用 delete 移除它, 但若是純全域物件的屬性, 就可以用 delete 移除

這樣的差異很合理, 因為以 var 宣告的全域變數是真的全域變數, 如果可以刪除, 就不再是可以在程式中任何地方取用的全域變數了, 但是全域物件本來就是一個 JavaScript 物件, 自然可以隨意增刪屬性。

小結

以上我們就把宣告變數的幾種方法介紹完了, 希望有助於釐清為什麼這裡可以使用這個變數、或者是為什麼這個變數變成沒有定義的疑惑。簡單來說, 為了避免意外, 建議在程式中都只以 letconst 宣告, 不要使用 var, 也不要隨意幫全域物件新增屬性。

本文分享自 DEV 範例與詳細說明請見原文