# Day JavaScript var vs let JS 的 var 以及 let 主要在以下四點有差異: 1. 作用範圍 Scope 2. 變數提升 Hoisting 3. 執行環境 Execution Context 4. 宣告 declaration ## 作用範圍 Scope: 在區域內的作用範圍不同。 - var : 以 function( ) 為作用範圍 - let : 以 block { } 為作用範圍 簡單來說,function 可以關住 var 及 let (因為 function 也有使用到 { } ),而 block 只能關住 let。 ~~當 var 沒被 function 關住時~~ 當 var 的作用範圍在 block { } 時,var 無法被關住,會溢出到外面變成全域變數,JS 會自動在全域環境下宣告一個 i 變數出來。 範例如下: ```js= 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 變數,導致噴錯。 ``` ## 變數提升 Hoisting: JS裡才特有的東西,若用 var 將變數定義在函式下方,執行結果不會跑出 not define,而是跑出undefined,是因為 JS 把變數提升移動到函式上方(大眾說法),但其實裡面的程式碼並不會上下跑動。 JS執行程式時會經歷兩段時期: 1. 建立期:JS 會先分配記憶體給宣告的變數及函式,其中函式又會比變數優先被宣告。 在建立期會做兩件事情(依照 1A、1B 的順序): 1A:註冊名稱 = 建立罐子,JS 會宣告變數,但不會賦值給變數。 1B:初始化 = 給他空氣,因為沒有值的關係,這個變數的值會是 undefined。 2. 執行期:執行程式碼。 在執行期也會做兩件事情(依照程式碼由上至下的順序): 2A:把宣告變數裡的值指定給變數。 2B:執行函式。 - var 有變數提升,在 1B 初始化的時期,變數會被賦予 undefined,即使把宣告寫在後面也能執行,不會出錯。 - ~~let 沒有變數提升~~ let 則是要等到 2A 賦值之後,才能進行 1B 的初始化,在那之前會被 TDZ 蓋住,導致 JS 無法讀取他,最後會出錯。 ```javascript= 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 ``` 為什麼同樣是宣告,用 let 宣告不會有變數提升? => 用 var 在宣告時,變數會變成全域變數。 => 用 let 宣告時,變數會變成區域變數,JS 在 1A 時會用一個 TDZ (Temporal Dead Zone 暫時死區) 把變數蓋住,當給予值後才能把蓋子打開。 ```javascript= 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 => 被印出 ``` ## 執行環境 Execution Context: JS 裡最大的執行環境稱為全域執行環境 Global Execution Context 。 全域執行環境底下又可分為: - Object Environment Records:全域物件環境 - var 會在此環境下宣告變數,在瀏覽器中可以用 window 物件執行(在 node.js 可以用 global 執行)。 - Declarative Environment Records:宣告環境 - let 會在此環境下宣告變數,無法用 window 或 global 物件執行,因為 window 及 global 是全域物件環境內的物件。 ```js= var a = 1; let b = 2; console.log(window.a); // 印出 1 console.log(window.b); // 印出 undefined ``` ## 宣告 declaration: 在同作用範圍內: - var 可以重新宣告。 - let 無法重新宣告。 ```js= var a = 1; var a = 2; // 可順利執行 let b = 3; let b = 4; // 印出 "error" SyntaxError: Identifier 'b' has already been declared ``` ###### tags: `13th鐵人賽` `網頁前後端寶石庫-礦坑補完計畫`
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up