這兩天會介紹到 JS 內 var 與 let 的差異,今天跟明天分別介紹兩點。
在區域內的作用範圍不同。
簡單來說,function 可以關住 var 及 let (因為 function 也有使用到 { } ),而 block 只能關住 let。
當 var 的作用範圍在 block { } 時,var 無法被關住,會溢出到外面變成全域變數,JS 會自動在全域環境下宣告一個 i 變數出來。
for (var i = 0; i < 3; i++) {
console.log(i)
// 印出 0, 1, 2
}
console.log(i)
// 印出 3
// 因為 { } 無法關住 var ,造成 i 溢出。
// 在上個迴圈的 i 遞增到3就停止了,JS 會在全域環境下生出 var i = 3。
// 導致最後外層的 console.log 印出3
for (let j = 0; j < 3; j++) {
console.log(j)
// 印出 0, 1, 2
}
console.log(j)
// 印出 "error" ReferenceError: j is not defined
// 因為 let 被 { } 關住,所以 j 不會溢出。
// 外層沒有 j 變數,導致噴錯。
JS裡才特有的東西,若用 var 將變數定義在函式下方,執行結果不會跑出 not define,而是跑出undefined,是因為 JS 把變數提升移動到函式上方(大眾說法),但其實裡面的程式碼並不會上下跑動。
JS執行程式時會經歷兩段時期:
建立期:JS 會先分配記憶體給宣告的變數及函式,其中函式又會比變數優先被宣告。
在建立期會做兩件事情(依照 1A、1B 的順序):
1A:註冊名稱 = 建立罐子,JS 會宣告變數,但不會賦值給變數。
1B:初始化 = 給他空氣,因為沒有值的關係,這個變數的值會是 undefined。
執行期:執行程式碼。
在執行期也會做兩件事情(依照程式碼由上至下的順序):
2A:把宣告變數裡的值指定給變數。
2B:執行函式。
console.log(a)
var a = 1
// 印出 undefined
// 程式碼由上開始往下讀取
// 1.跳過 console.log
// 2.執行 1A var a
// 3.執行 1B var a = undefined
// 4.回到 console.log ,執行 2B undefined => 被印出
// 5.執行 2A a = 1
console.log(a)
let a = 1
// 印出 Cannot access 'a' before initialization
// 程式碼由上開始往下讀取
// 1.跳過 console.log
// 2.執行 1A let a 並且給他一個TDZ
// 3.執行 1B 變數a因為被 TDZ 蓋住,所以無法執行初始化
// 4.回到 console.log 執行 2B ,因為a被蓋住無法進行 1B 的初始化
// ReferenceError: Cannot access 'a' before initialization => 被印出
參考:
[1]What's the difference between using "let" and "var"?