[教學]var、let、const之間的比較
不要再亂設定變數了啊~設定好變數可以幫你減少bug喔!
前言
重新開始學習JS我才發現有很多小細節是需要好好打底的,所以我去報名了六角學院的Javascript工程師養成直播班從基礎開始學習,跟著老師的步調再加上每日作業、每週作業一定可以飛速成長的~
接下來幾次的更新會注重在JS上,因為就連寫文章也是學習JS的一環(雖然我不確定能不能跟得上老師的進度生產文章,全職學習真的沒那麼多時間R~~ 但我還是會努力跟上進度的!
本次探討的東西是非常基礎的宣告變數,但越是簡單的東西越要小心,魔鬼藏在細節中,你的程式碼出現bug很有可能就是因為變數使用錯誤的關係喔!今天就讓我們來了解var、let、const之間的差異吧~
目錄:
從ES5到ES6
什麼是ES5、ES6??
在了解這兩者之間的差異前,我們需要先來認識ECMAScript。ECMAScript提供腳本語言需要遵守的細節、規則以及規範,ECMAScript每年都會發布一次新的版本,而比較知名的版本就是第五版的ES5以及第六版的ES6。
更詳細了解ECMAScript可以參考Day2 [JavaScript 基礎] 淺談 ECMAScript 與 JavaScript,裡面有詳細講解ECMAScript的歷史和制定流程。
目前的瀏覽器普遍支援ES5、ES6,甚至支援更新的ES7,大家可以安心使用。這裡我列出從ES5更新到ES6的主要改動:
ES5 | ES6 | |
---|---|---|
類型 | 空值(null)、未定義(undefined)、布林值(boolean)、數字(number)、字串(string)、物件(object) | 引入新的類型:符號(symbol)用來表示唯一值 |
變數 | 只能使用var來定義變數 | 新增let、const,能夠更嚴謹的定義變數 |
箭頭函數 | 使用function、return來定義函數內容 | 可用"=>“等符號代表function |
迴圈 | 使用for迴圈、for in迴圈、forEach迴圈… | 新增for of迴圈 |
從上方表格可得知ES6是基於ES5上新增了部分的功能,而我們今天就先來探討變數的部分,其他的之後後再說(如果老師有出的話我就一定會更新 XDD~
變數的有效範圍
宣告變數的位置是會影響到他們的作用範圍,有效範圍主要分成「全域變數」、「區域變數」兩種:
- 全域變數(Global Variable):在
函式外
宣告的變數。整個程式中都可以被存取與修改。 - 區域變數(Local Variable):在
區塊內
等被 { } 包起來的地方宣告的變數。此變數只能提供在所屬的function函式中執行,不提供給functionc函式以外呼叫使用,當function函式執行完後,記憶體只會保留其執行的結果,變數的部分則會被記憶體消除釋放掉。
由上方的程式碼可以看出全域變數可以在整個程式碼內取得到;而區域變數只能在該函數(區域)取得,在函數(區塊)外就取得不到,因此會報錯顯示「not defined(沒有被定義)」。
到這裡補充完ECMAScript、變數的有效範圍的相關知識,我們終於可以進到下一趴了~~
初始值(initializer)
var
、let
不需要給初始值,它們的預設是undefined。const
必須有初始值,因為是常數,自然是要有固定不變的常量。
作用域(scope)
- 函式作用域(function scope):
var
屬函式作用域,唯有在函式(function)內才使用,作用範圍為區域性(local);若在函式外宣告,其作用範圍就變成了全域性(global)。 - 塊級作用域(block scope):
let
、const
屬塊級作用域,以塊級(block)當作最小單位來切分,也就是用大括號{}
來區分。
以下是函式作用域(function scope)的範例:
再來對比塊級作用域(block scope)就可以知道兩者差在哪:
上面的程式碼可以看到let
、const
並無法在函式外被呼叫,因為function的大括號也算是一種block scope。
在if
、else
、for
、while
等塊級區域(block scope)使用var宣告變數是會污染全域變數的。我們來看看下列的程式碼:
但我覺得那是工程師沒有仔細注意var
是function scope,它的最小單位是以function來區分的,而if
、else
、for
、while
等塊級區域(block scope)則是以大括號{}
來區分的,因此在block scope裡面的var
當然會繼續往上加R~
這裡再舉一個例子,這樣會比較好理解:
從上面的程式碼可以了解var
確實為function scope,因此在函式內的block scope是無法攔下i
的,它會繼續增加;而在函式外面卻是找不到i
的。
重複賦值(reassigned)
var
、let
可以重複賦值,賦予的值稱「變數」,顧名思義是可以改變的數字。const
無法重複賦值,賦予的值稱「常數」,常數又稱定數,是指一個數值固定不變的常量,如圓周率等,這類的數值是無法經過改動的。
這裡需要特別注意一點,const
雖然不能夠重複賦值,但它若是「物件型別」的物件或陣列,則『看起來就能夠重複賦值』,但它並沒有!!!!!!!!
由上方的程式碼可以看到,在arr2新增4,結果arr1的值也發生了改動,這樣確實看起來像是const
可以重複賦值。然而實際上卻不是如此,第二行程式碼的意思為將arr2「指向」arr1現在指向的記憶體位置,所以兩者皆指向同一個記憶體。「用 const 宣告的變數,不能改變其值」,對於 object 來說是指:「物件/陣列裡面存的 『記憶體位置』 不能改變」,因此這裡不會改變記憶體位置,改變的而是值。
我之後會補上傳值、傳參考的文章,想要了解詳情之後可以去看看。
重複宣告(redeclared)
var
可以重複宣告。let
、const
不可重複宣告。
變量提升(hoisting)
var
能夠變量提升。let
、const
無法變量提升。
簡單來說使用變量提升,程式碼就會自動幫你編譯:
以上程式碼可以理解為:「編譯階段會放入記憶體存著,但是只存宣告,不能存變數」。
結語
最後稍微總結這三者的使用方式。
var
:不會受限在塊級作用域(block scope)內,可能會汙染全域變數。不管哪個作用域(Scope)都可以存取,可以重複宣告。let
:所宣告的變數只有在塊級作用域(block scope)內有效,不會產生全域變數,無法在同一層 Block 重複宣告變數。const
:具備let
所有的特性。在一開始宣告時就必定要指定給值,不然會產生錯誤,宣告後不能更改值。
最後放上整理大表格結束這一回合~
var | let | const | |
---|---|---|---|
初始值(initializer) | ✘ | ✘ | ✔︎ |
函式作用域(function scope) | ✔︎ | ✔︎ | ✔︎ |
塊級作用域(block scope) | ✘ | ✔︎ | ✔︎ |
重複賦值(reassigned) | ✔︎ | ✔︎ | ✘ |
重複宣告(redeclared) | ✔︎ | ✘ | ✘ |
變量提升(hoisting) | ✔︎ | ✘ | ✘ |
參考資料:
Day2 [JavaScript 基礎] 淺談 ECMAScript 與 JavaScript