大頭照

你好,我是米米

菜雞前端工程師

[教學]var、let、const之間的比較

不要再亂設定變數了啊~設定好變數可以幫你減少bug喔!

米米

JS、變數教學

前言

重新開始學習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)

  1. varlet不需要給初始值,它們的預設是undefined。
  2. const必須有初始值,因為是常數,自然是要有固定不變的常量。

作用域(scope)

  1. 函式作用域(function scope):var屬函式作用域,唯有在函式(function)內才使用,作用範圍為區域性(local);若在函式外宣告,其作用範圍就變成了全域性(global)。
  2. 塊級作用域(block scope):letconst屬塊級作用域,以塊級(block)當作最小單位來切分,也就是用大括號{}來區分。

以下是函式作用域(function scope)的範例:

再來對比塊級作用域(block scope)就可以知道兩者差在哪:

上面的程式碼可以看到letconst並無法在函式外被呼叫,因為function的大括號也算是一種block scope。

ifelseforwhile等塊級區域(block scope)使用var宣告變數是會污染全域變數的。我們來看看下列的程式碼:

但我覺得那是工程師沒有仔細注意var是function scope,它的最小單位是以function來區分的,而ifelseforwhile等塊級區域(block scope)則是以大括號{}來區分的,因此在block scope裡面的var當然會繼續往上加R~

這裡再舉一個例子,這樣會比較好理解:

從上面的程式碼可以了解var確實為function scope,因此在函式內的block scope是無法攔下i的,它會繼續增加;而在函式外面卻是找不到i的。

重複賦值(reassigned)

  1. varlet可以重複賦值,賦予的值稱「變數」,顧名思義是可以改變的數字。
  2. const無法重複賦值,賦予的值稱「常數」,常數又稱定數,是指一個數值固定不變的常量,如圓周率等,這類的數值是無法經過改動的。

這裡需要特別注意一點,const雖然不能夠重複賦值,但它若是「物件型別」的物件或陣列,則『看起來就能夠重複賦值』,但它並沒有!!!!!!!!

由上方的程式碼可以看到,在arr2新增4,結果arr1的值也發生了改動,這樣確實看起來像是const可以重複賦值。然而實際上卻不是如此,第二行程式碼的意思為將arr2「指向」arr1現在指向的記憶體位置,所以兩者皆指向同一個記憶體。「用 const 宣告的變數,不能改變其值」,對於 object 來說是指:「物件/陣列裡面存的 『記憶體位置』 不能改變」,因此這裡不會改變記憶體位置,改變的而是值。

我之後會補上傳值、傳參考的文章,想要了解詳情之後可以去看看。

重複宣告(redeclared)

  1. var可以重複宣告。
  2. letconst不可重複宣告。

變量提升(hoisting)

  1. var能夠變量提升。
  2. letconst無法變量提升。

簡單來說使用變量提升,程式碼就會自動幫你編譯:

以上程式碼可以理解為:「編譯階段會放入記憶體存著,但是只存宣告,不能存變數」。

結語

最後稍微總結這三者的使用方式。

  • 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

[ 技術筆記 ] JavaScript|var / let / const 差異

[JS學徒特訓班] JavaScript ES6 : var, let, const 差異

感謝抖內

BUY ME A COFFEE
comments powered by Disqus
comments powered by Disqus

advertisement

recent post

categories

advertisement

about

你好,我是米米,是個剛畢業就已經成為社畜的前端工程師==