[JS] 變數宣告方式:let、const、var

JavaScript 過去只有 var 一種變數宣告方式,直到 2015 年發表的 ECMAScript 2015(ES2015),第 6 版,又被稱為 ECMAScript 6(通常簡稱為 ES6 ),才有 letconst 兩種新的變數宣告方式,這個版本有相當多的革新,現在常用的箭頭函式、樣板字串…等都包含在其中。

參考資料: Wiki - ECMAScript


💎 Can I Use?

雖然 2015 年距今已經超過 6 年了,但是仍有些企業或公司在使用 IE 這類過時的瀏覽器,letconst 在 IE 11 只有部分支援、 IE 10 以下版本則是完全不支援,如有支援需求就需要搭配 Babel 來轉換成兼容的程式碼。

參考資料: Can I Use


💎 變數宣告方式的差異

var 規範較鬆,有許多小陷阱需要小心使用,letconst 有了進一步的規範,可以針對不同需求運用,使用上較安全,兩者間有5個主要的差異在下個段落逐一說明。:

  • 可否重複宣告
  • 可否重新賦值
  • 是否需要初始值
  • 作用域的範圍
  • 提昇(Hoisting)機制的差異

🔸 1、重複宣告

  • var 可以重複宣告同一個變數名稱,後者會覆蓋前者,而且程式不會報錯,使用起來較危險,萬一不小心使用了相同的名稱,可能造成其他段落程式碼出錯。

    1
    2
    3
    var a = 1;
    var a = 2;
    console.log(a); // 2
  • letconst 不允許重複宣告,使用起來較安全。

    1
    2
    3
    let b = 1;
    let b = 2;
    // Uncaught SyntaxError: Identifier 'b' has already been declared

🔸 2、重新賦值

  • 如果不知道『常數』是什麼,可以先看一下維基百科的說明。

    摘錄自維基百科:
    常數,又稱定數(Constant),是指一個數值固定不變的常量,例如圓周率,與之相反的是變數。

    參考資料: Wiki - 常數

  • 過去只有 var 時,如果想要宣告一個不能被變更的常數,通常會用全部大寫,加上 _ 連接單字來標示,但是名稱只能幫助辨識,實際操作並不具有常數的限制。

    1
    2
    3
    var DO_NOT_TOUCH_ME = 'X';
    DO_NOT_TOUCH_ME = '我偏要改';
    console.log(DO_NOT_TOUCH_ME); // 我偏要改
  • ES6 提供的 const 宣告方式可以實際的宣告一個常數,有了 const 之後不需要使用大寫格式命名來區別是不是常數,看宣告方式即可(視團隊開發時的規範而定);而 let 則是和 var 一樣可以重新賦值。

    1
    2
    3
    const doNotTouchMe = 'X';
    doNotTouchMe = '我偏要碰';
    // Uncaught TypeError: Assignment to constant variable.
  • const 的使用時機:對 JS 新手來說,大概只會想到圓周率、太陽數量…等,在撰寫時遇到下列的情形都建議使用 const 宣告。

    • DOM:使用 querySelector 這類方法取得的 DOM 如果被改變,容易造成邏輯混亂,維護困難。
    • 陣列:使用陣列方法來操作,避免被 = 賦值給覆蓋掉。
    • 物件:使用物件方法來操作,避免被 = 賦值給覆蓋掉。
    • 函式表示式:避免被 = 賦值給覆蓋掉。

    延伸問題:
    使用 const 宣告的變數應該不能被變更才對,為什麼『陣列』和『物件』要使用 const 來宣告?
    Ans:
    變數裡面存放的陣列和物件並不是實體,而是指向實體的記憶體位置,就像是變數名稱存放了帝寶的地址,透過這個變數名稱的值能到達帝寶的實體位置,對大樓做變更操作。
    詳細可以參考我的另一篇文章 參數傳遞方式 Call by what?


🔸 3、初始值

  • 常數是不能更動的值,在一開始設定好值也是相當合理,因此 const 在宣告的時候一定要賦予值,varlet 則無此限制。
    1
    2
    const a;
    // Uncaught SyntaxError: Missing initializer in const declaration

🔸 4、作用域

  • 作用域(Scope)是變數可以被使用的區域,也代表著在相同的作用域才會有重複命名的衝突問題,只要作用域不同就可以宣告相同名稱的變數。
    • var:函式作用域,只在 function 間區隔作用域,範圍大,不好區分。
    • let、const:區塊作用域,在 {…}(大括弧)間區隔作用域,範圍小,容易區分。

詳細說明可以參考我的另一篇文章: [JS] 作用域(Scope)與範圍鏈(Scope Chain)


🔸 5、提昇(Hoisting)

  • JavaScript 在進入執行階段前會將文件中所有宣告的變數、函式(函式陳述式)提前到最上方,差異如下:
    • var:變數提到最上方後會實體化(寫入記憶體,但尚未賦值),在實際執行到該行變數宣告的程式碼前可以被取用(取值結果為 undefined)。
    • let、const:變數提前到最上方後不會實體化,在實際執行到該行變數宣告的程式碼前不可以取用(取值結果為 執行階段錯誤),這段不能取用的期間又稱為暫時性死區(TDZ)

詳細說明可以參考我的另一篇文章: [JS] 提昇(Hoisting)機制


💎 總結

整理後的變數宣告方式差異列表如下:

var let const
重複宣告
重新賦值
強制賦予初始值
作用域 function { } { }
提升機制 可被取用 TDZ TDZ

以上是我對變數型別的一點認知,如有錯誤或是補充的知識點,也歡迎大家不吝指教,謝謝!

參考資料: 六角學院-JavaScript 那個 let, const, var 到底差在哪?