JavaScript 因為歷史悠久, 所以你可能會遇到經過多人更改過的 JavaScript 程式, 裡面混雜了不同時期 JavaScript 的語法, 導致有時候 JavaScript 程式就是難懂, 本文將針對宣告變數的幾種方法加以說明, 期望能讓大家快速理解其中的差別。
過去最常看到的變數宣告方是就是使用 var
, 它宣告的變數是函式層級, 也就是只要離開宣告時所在的函式, 這個變數就失效了
如果在函式外使用 var
宣告變數, 它就會變成全域變數, 在程式內任何地方都可以取用
你也可以把宣告和設定初值分開來, 不一定要同時完成
你也可以重複宣告同一個變數, 只要沒有設定新的值, 就會保留原值
變數有一個我其實不知道有什麼用途, 但是很多人喜歡拿來考別人的功能, 叫做 變數提升 (variable hoisting)
, 會把宣告變數的動作提升到執行其他程式前先完成, 意思就是在進入變數的有效範圍內時, 會在執行第一行程式前就先宣告變數。因此, 在執行第一行程式的時候, 變數就已經存在了。
以 var
宣告的全域變數會成為全域物件的屬性,不過這個屬性是不可設定 (non-configurable) 的, 也就是不能使用 delete
移除
所謂的區塊, 就是由一對大括號括起來的區域, 使用 let
宣告的變數只要出了所在的區塊, 就會失效
在大部分的情況下, 我們很容易辨識區塊, 不過在像是 for
的敘述中, 初始設定也是區塊的一部份, 因此在初始設定內宣告的變數在 for
結束後也一樣會失效
在任何區塊外使用 let
建立的變數一樣是全域變數, 可在程式中任何地方取用
以 let
宣告變數也一樣具有變數提升功能, 但是並不會設定初值, 在使用變數前一定要先透過 let
宣告
以 let
宣告的變數並不會像是以 var
宣告的變數那樣成為全域物件的屬性
你也可以使用 const
宣告變數, 不過這種變數如同 const
字面所示, 是不能變的, 中文翻譯為常數
以 const
宣告常數時必須一併設定初值, 不能將宣告與設定初值分開進行
請特別注意, 不能變更以 const
宣告的常數指的是不能重新設定常數本身, 如果常數的內容是一個物件, 你還是可以變更物件內的屬性
JavaScript 是很寬鬆的, 你甚至會看到有些程式中根本沒有宣告就直接設定變數的值
之所以會有前述範例的結果, 是因為當 JavaScript 看到識別字時, 會一層層的往外找尋是否有符合該名稱的宣告,如果在全域變數裡也找不到, 就會往全域物件 globalThis
找它的屬性, 這也是為什麼你可以直接以 alert
叫用定義在 globalThis
物件內的 alert
你可以在任何地方用這種方式幫全域物件增加屬性, 並且以像是全域變數的方式使用該屬性。也就是說, 若不使用 var
、let
、const
宣告而直接設定值, 並不會建立變數, 而是設定全域物件 globalThis
的屬性。這樣的作法看起來好像很方便, 隨時想用就用, 但是卻容易造成混淆, 搞不清楚到底是在哪裡設定初值, 若要避免這個問題, 可以強制使用嚴格模式
你可能會想到, 前面不是有提到以 var
宣告的全域變數也會變成全域物件的屬性, 這樣和剛剛提到單純全域物件的屬性不是一樣嗎?還記得前面說明過, 以 var
宣告的全域變數會成為全域物件中不可設定的屬性, 具體的表現就是你無法用 delete
移除它, 但若是純全域物件的屬性, 就可以用 delete
移除
這樣的差異很合理, 因為以 var
宣告的全域變數是真的全域變數, 如果可以刪除, 就不再是可以在程式中任何地方取用的全域變數了, 但是全域物件本來就是一個 JavaScript 物件, 自然可以隨意增刪屬性。
以上我們就把宣告變數的幾種方法介紹完了, 希望有助於釐清為什麼這裡可以使用這個變數、或者是為什麼這個變數變成沒有定義的疑惑。簡單來說, 為了避免意外, 建議在程式中都只以 let
、const
宣告, 不要使用 var
, 也不要隨意幫全域物件新增屬性。
本文分享自 DEV 範例與詳細說明請見原文