--- tags: JavaScirpt, hexo部落格, 六角筆記王 title: ES6 變數宣告與全域環境 --- # ES6 變數宣告與全域環境 JavaScirpt 身為一種廣泛使用的程式語言,好上手也最容易踩雷,從 ES5 進化到 ES6 後增加了變數宣告方式與一些語法糖,其歷史沿革已有很多前輩說明,為了方便之後描述,以下 JavaScript 簡稱為 JS。 ## ▶ JS 變數宣告 ### ✏ var 在 ES5 時期,要宣告一個變數會使用 var 作為開頭,但它有個缺點,就是它會建立在全域,在後續開發上會讓造成混淆,像是以下例子: ```javascript var a = 1 console.log(a) // 1 console.log(window.a) // 1 // window是 JS的最上層,也就是全域 // 它有很多 JS內建的事件與函式 ``` 透過瀏覽器(開發者模式)來看,會發現在 window中找得到 a 這個變數,這很可能讓後續寫下的變數或者函式抓到同樣的變數[^註1],進而造成不必要的錯誤。不過,它不是不能用,根據實際情況改變寫法才是我們要的。 順帶一提,若有安裝 ESLint 這類的檢查工具,這個宣告方式還是會被建議改成 let 或者 const。 [^註1]: 若函式裏頭未宣告且命名一個變數並賦予值,那麼此變數就會在全域環境中建立一個該變數的名稱(這個行為是 **Hoisting**,中文名為提升)。 ```javascript var b = function (){ a = 2 var c = 22 } b() console.log(a) // 2 console.log(c) // c is not defined // 執行 b 函式時,全域環境中建立了名為 a 的變數 // 而變數 c 是在函式內宣告,因此在"全域環境"中找不到變數 c ``` ### ✏ let 在 ES6 中,新增了 let 與 const,這邊先介紹 let。 #### 特性 - 只在某區塊(例如函式)中有作用 - 無法重複宣告同樣變數名稱 - 變數的值可改變 #### 範例 為了解決 var 所帶來的困擾,使用 let 來做為變數宣告會是一個比較好的方式,它的作用範圍被限制在某個區塊中,就算不在函式中宣告,在 window 中也找不到利用 let 所宣告的變數。以下為範例 : ```javascript let a = 1 console.log(a) // 1 console.log(window.a) // undefined ``` ### ✏ const #### 特性 - 無法重複宣告 - 變數的值不可改變 - 若賦予的值為陣列或物件,可以改變其內部屬性 使用 const 宣告的變數為**常數**,無法改變其值,類似唯讀。 ## ▶ 全域環境 上述的範例中會看到 window.a,這其實是物件的寫法,利用 var 來宣告變數時,會在 window,也就是全域環境中新增一個物件屬性,為什麼會提到物件? 因為在說明 let 時,自己不禁有個疑問,`let a` 有宣告,但在全域中卻找不到,那它去哪裡了? ### ✏ 全域之複合環境 [這裡](https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/30)似乎有相關的說明。目前自己的理解是,全域環境中是一個複合環境,包含 : - 物件環境 Object Environment - 聲明環境 Declarative Environment ### ✏ 範例 ```javascript= var a = 10 var b = function(){ console.log(a) } ``` 以表格來看的話,類似像這樣 : | 聲明環境 | 物件環境 | | -------- | -------- | | a | 10 | | b | funciton() | 而 JS是物件導向,以物件來看的話, ```javascript // 會在瀏覽器中的 Global 內發現它們 { a: 10 b: f() } ``` ### ✏ 瀏覽器中的 Scope 對於瀏覽器來說,當執行環境執行程式碼時,會在瀏覽器的 Scope 產生 Global 與 Script,而範例的執行環境就是全域環境,所以當變數沒有被告知用哪一種變數宣告,那麼就會根據 JS 規則將此變數建立在 Global,若在全域環境下也用 var 宣告,那麼就會是建立在 Global。 而使用 let 與 const 宣告時,它們會被建立在 Script,這就是為什麼無法在 window 中找到的原因,因為它們的建立規則不是建立在 Global。 ## 參考來源 > 1. [pvt5r486 - [JavaScript Weird] Day 2 — 全域執行環境與全域物件](https://medium.com/pvt5r486/javascript-weird-day-2-%E5%85%A8%E5%9F%9F%E5%9F%B7%E8%A1%8C%E7%92%B0%E5%A2%83%E8%88%87%E5%85%A8%E5%9F%9F%E7%89%A9%E4%BB%B6-428bc0d61085) > 2. [Ray - 淺談 var 與 let 的差異以及有無宣告變數的差異](https://hsiangfeng.github.io/javascript/20200425/539985371/) > 3. [realdennis - 一次說清楚 JavaScript 中宣告的各種提升行為(var、function、let/const)](https://medium.com/@realdennis/%E4%B8%80%E6%AC%A1%E8%AA%AA%E6%B8%85%E6%A5%9A-javascript-%E4%B8%AD%E5%AE%A3%E5%91%8A%E7%9A%84%E5%90%84%E7%A8%AE%E6%8F%90%E5%8D%87%E8%A1%8C%E7%82%BA-var-function-let-const-dd9175d063f0) > 4. [Fun Lee - 关于 const 和 let 声明的变量不在 window 上](https://github.com/Advanced-Frontend/Daily-Interview-Question/issues/30) {%hackmd S1DMFioCO %}