從前,JavScript 世界只有 var
變數...var
會發生「區域變數覆蓋全域變數」以及各種鬼故事,
例如這段程式碼:
var dirtyVariable = "🌍 Global variable here!";
function dirtyFunction() {
console.log("Hoisting:" + dirtyVariable);
var dirtyVariable = "🏠 Local variable here!";
console.log("Dirty Function:" + dirtyVariable);
return dirtyVariable;
}
dirtyFunction();
console.log("Global:" + dirtyVariable);
小知識:由於瀏覽器檢閱器(inspector)會回傳最後一個函數的回傳值,因此 console.log 沒有回傳值會顯示undefined
由於 Hoisting 提升機制,function 函式中 console.log 呼叫的 dirtyVariable 被宣告的環節會先被放在作用域的最頂部,但是並不會將其賦值。
同時,由於他是區域變數,區域的作用域範圍是函式,這是唯一能控制 var 作用域的方法(for 不行),並不會吃到全域變數的賦值。而 var 只要後面有宣告就不會報錯 //ReferenceError,這導致了輸出結果為 undefined。
Hoisting:undefined
Dirty Function:🏠 Local variable here!
Global:🌍 Global variable here!
即使在全域 (global) 已經宣告(declare)、而且賦值(assign),但那都是全域變數的事情。
在 function 作用域的區域變數中,local 的 dirtyVariable 在呼叫時直接宣告,但賦植不會ㄧ起提升上去。
但自從 ES6 (2015)
發表以來,我們有了動與靜的世界
動,代表的是變數 let
靜,代表的是常數 const
想堅持好的程式撰寫習慣,就得在能用 const
(constant) 的時候使用 const
。
例如 JavaScript 與 DOM 互動時,以 querySelector
抓取特定 class / id / tag name
讓 JS 與瀏覽器 Html 畫面產生聯繫,一接觸就不要分開 —— 當然是指在作用域內,例如閉包 (closure)中。
const 的宣告跟賦值必須同時完成。
let
則取代 var 的角色,例如應用在迴圈邏輯上,不會污染到全域去。一但放入作用域,let 的生命就在這些「括號」裡面,不會隨意溢出,稱為區塊作用域(block scope)。常用的脈絡例如狀態的管理,例如 let isLoading = false 避免事件不斷重複觸發,只在事件發生時短暫變回 true; 或者 let count = 0 去做各種計算,無論是頁數、計算、索引(index) 等等。
暫時死區 (TDZ, Temporal Dead Zone) 是聽起來很帥的名字,let/const 的變數提升在宣告賦值之前的呼叫
如果跟 var ㄧ樣,在宣告前就 console.log 取用、呼叫他們呢?const 跟 let 其實還是把他們提升到最上面,但給他們關廁所了,那間廁所就是暫時死區,會報錯呦。
const, let 跟不要再用的 var,就像 JavaScript 的御三家:
一個熱騰騰、鎔鑄,賦值不再改變
一個可以不斷變化
一個沒人在用