ㄟ問你喔,var, let 和 const 有啥不同?之二 (var 與 let 的比較)
在這一篇文章內,主要會著重在比較 var 和 let 之間的異同。
var 與 let 的差異一:var 為函式作用域,let 為區塊作用域
在接下來的兩個範例中,將解釋:
1. var 宣告的變數在函式作用域的範圍
2. let 所宣告的變數作用域在區塊作用域之內並得到結論:用 let 所宣告的變數範圍又更為聚焦、比 var 更為嚴謹。
這邊先以 var 在 if 條件式內宣告一個變數:
這也意味著 var 宣告的變數,它的作用域範圍是在整個函式之內,但只要在函式之外的範圍,就讀不到它的值了,故顯示 not defined。
這邊再以 let 在 if 條件式內宣告一個變數:
註:if 判斷式及 for、while 迴圈皆有大括號語法。
不過 var 的函式作用域可能會產生什麼問題呢?
為什麼在 ES6 問世後,越來越少人用 var 來宣告變數?究竟原因為何?
我們或許可試著從接下來的範例來窺知一二:
假如在全域範圍(程式碼第 2 行)先以 var 宣告一個變數 myCarColor 賦予值為 ‘red’,在 if 判斷式內又再一次宣告 myCarColor 並賦予值為 ‘black’,最後印出 myCarColor 得到的結果,是 ‘black’。
由此可得知,以 var 宣告的變數,在這些有大括號 { } 的程式碼(像是 if 判斷式及 for、while 迴圈)作用域範圍不夠精確,將導致大括號內的程式碼會污染到全域變數的問題。
這就不難了解為什麼在 ES6 後,越來越多人愛用 let & const 來宣告變數了。但理解 var 的性質仍是必要的,因為總難免會遇到需要維護舊程式碼的情況。
var 與 let 的差異二:var 可重複宣告同一個變數,let 不行
在接下來的第一個例子中,將解釋:
var 宣告過的變數,可再一次用 var 重複宣告在第二個例子中,將解釋:
let 宣告過的變數不能再用 let 重複宣告第二次得到結論,let 宣告變數的優點是:
let 語法會替開發者自動過濾,提醒這個變數在前面已被使用過。
第一個例子:
以 var 宣告過的變數可以再用 var 重複宣告一次,且變數也能重新賦值。
第二個例子:
以 let 宣告的變數,不可再度重複用 let 宣告,但變數可以重新賦值。
var 與 let 的差異三:hoisting 的結果不同
在開始講 var 與 let 的第三個差異開始之前,要先了解一下,變數宣告的過程 — — 變數的資料究竟要如何儲存到記憶體?
變數的宣告過程與記憶體的原理
當用 var 宣告一個變數 myFavoriteSinger 但不給它值,在變數宣告的同時電腦也會開啟一個記憶體空間,只是這時還沒有被賦予值,記憶體空間內的資料會是 undefined(如圖 1 所示)。
然而,當變數被賦予值 var myFavoriteSinger = ‘Bruno Major’,此時變數就會轉向另一個記憶體儲存 ‘Bruno Major’ 這一個字串(如圖 2 所示)。
看完了變數宣告的過程,進入正題,何謂「抬升(hoisting) 」?
一般來說,程式碼的讀取順序會是由第一行到最後一行,但假設今天在第六行用 var 宣告一個變數 a,不過從第二行就要求印出這個變數 a 的值,結果卻會顯示為 undefined,代表這個變數 a 已被讀取到,只是此時它的值為 undefined。
同樣地,在第七行用 let 宣告一個變數 b,但在第三行就要先印出 b 的值,得到的結果卻與 var 宣告的變數 a 不同,會顯示「在 ‘b’ 初始化之前無法讀取到 ‘b’ 的值」。
其實不管是用 let 或 var 來宣告的變數都有「抬升」,只是 a 會印出 undefined,而用 let 宣告的變數 b 會顯示「在 ‘b’ 初始化之前無法讀取到 ‘b’ 的值。」
特別值得注意的地方是,被 var 宣告的「變數 a 」有抬升,但變數 a 的值是沒有一起被抬升的,因為第二行的console.log(a) 並沒有印出在第五行 a 賦予的值 (30)。
註 1:這邊若有想要更深入了解有關抬升的概念,可參閱:我知道你懂 hoisting,可是你了解到多深?註 2:function 函式也有這種狀況,但在本文將不會討論函式的抬升。
好了,看完了三個 var 與 let 的差異後,接著在下一篇,再繼續討論 const 跟var, let 又有什麼不同吧。