在學習JavaScript的人在查找資料時一定都會看到 var
、 let
、 const
這些宣告變數的方式,為什麼宣告變數會有這麼多方式呢,以下就讓我們來好好的了解一下這三種宣告方式的差異點吧
變數
在說到他們間的差異時,先來複習一下什麼是變數。
變數就是我們用來儲存資料的基本單位。
就像我們在搬家時,都會在紙箱上面寫上這箱裡面裝的是什麼,這樣我們在之後整理東西就會比較迅速;而變數就像是那個有寫名字的紙箱,用來存放我們想要存放的資料。
在命名變數的名稱的時候,我們會讓變數是一個有意義的名稱,來提高程式碼的可讀性。另外我們在命名時還要避開JavaScript保留字 (Reserved Words) 與關鍵字 (keyword)。
下面是一段宣告變數的程式碼:
1 | let myBirthday = '1988/05/18' |
讓我們看到 let
、=
跟 myBirthday
,他們三個分別對應到的是對變數的宣告(declare)、指派(assign)與命名慣例(naming convention),接下來我們就照著這三個分類來做解釋。
宣告(declare)
ES6前的時代
在ES6前,我們在宣告變數時都是使用 var
,宣告的方式也跟現在一樣,如下:
1 | var myBirthday = '1988/05/18' |
疑,既然以前的寫法跟現在的寫法一樣,那為什麼要改呢?
最主要的原因就是 scope 的不同,**var
** 宣告的變數具有函式作用域(function scope),這意味著它們在函式內部可以被訪問,而不論它們是否在函式中聲明。這可能導致變數被提升(hoisting)到函式的頂部,可能引發意外行為或錯誤。
1 | function func() { |
如果我今天用的是let來宣告,則是會出現error:
1 | function func() { |
至於為什麼var宣告的不會出現error,這是因為a這個變數被提升(hoisting)了。
另外還會因為scope衍伸出下列狀況:
- 全域變數: 使用
var
宣告的變數在全域作用域內都可見,這可能導致變數名稱衝突,特別是在多個 JavaScript 檔案中。 - 重複宣告: 在同一作用域內重複使用
var
宣告同一個變數,不會引發錯誤,而是視為同一個變數,可能導致錯誤的邏輯。 - 無 block scope:
var
宣告的變數無法在區塊(例如 **if
、for
**)內建立新的作用域,這可能導致意外的變數共享和作用域問題。
scope 跟 hoisting 詳細的說明我會後面在做解釋(主要是講下去整篇會太長,而且scope跟hoisting蠻適合拉出來說,之後要複習也方便)
ES6時代
ES6發布之後,JavaScript有了區塊域(block)的概念,因此我們捨棄了無法在block內設立新的scope的var
,取代它的就是 let
跟 const
。
let、const特性
- 區塊作用域(block scope)
- 變數會提升,但若未宣告該變數時,就去提取該變數便會報錯,而非回傳
undefined
- 不允許重複宣告
- 全域變數不會成為
window
的屬性
當我們使用 let
關鍵字宣告變數時,代表我們預期資料是可以被改變的。
與let
相反,當我們使用 const
來宣告時,我們預期這組資料不能被改變,也就是常數(constant)的概念。
區塊作用域(block scope)
區塊作用域指的就是大括號{}
之間的區域,這個時候變數就只存活在{}
這個括號裡,{}
外就不能調用。
我們來看一個非常簡單的例子:
1 | { |
再來一個例子,相信大家會更了解:
1 | function func() { |
變數提升,但若未宣告該變數,會回傳錯誤,而非undefined
使用let
、const
、var
來宣告變數,都會提升至作用域的最高處。不同的是,如果我們沒有宣告就直接使用該變數時,var會回傳預設值undefined
,但const
和let
會報錯。
不允許重複宣告
如果該變數已經被宣告過,就不能再宣告。let
和const
都一樣。
1 | let food = 'apple'; |
全域變數不會成為window
的屬性
用var
宣告全域變數,會成為window
的屬性,但let
和const
不會。
指派(assign)
在第一次接觸變數的賦值時,我一直是把=
看作是等於
,但越學越覺得有點奇怪。
首先,讓我們把最一開始那段程式碼拆解一下:
1 | let myBirthday |
這邊我一開始學習時會把它理解成:myBirthday 等於 ‘1988/05/18’。
但這時候問題來了,當我把這個變數改變裡面的值的時候:
1 | myBirthday = '2000/05/18' |
他會印出:2000/05/18。
但明明myBirthday 是等於 ‘1988/05/18’,為什麼我可以改變它?
這才讓我發現我在解讀這行code的方式可能不是那麼正確。
現在我會把這行解讀成:我把’1988/05/18’這個字串指派(assign)給myBirthday這個變數。
命名慣例(naming convention)
在 JavaScript 中,我們在為變數命名時,需要注意以下幾點:
特殊符號
可以使用錢符 $
、底線 _
當成首字。如 $myBirthday
、_myBirthday
。
大小寫
在 JavaScript 裡,大小寫是有區分的,像是 MyBirthday
與 myBirthday
會被視作不同變數。
JavaScript 的保留字
在前面有提到,JavaScript 會有一些字作為特定的用途,而這些單字就不能拿來做為變數的名稱。
不能用數字開頭
數字不能作為變數開頭。
兩個單字使用camelCase 命名法
前面有提到讓變數是一個有意義的名稱,來提高程式碼的可讀性
。
因此在變數的命名上有時候我們就會有兩個單字,但如果我們這樣寫:
1 | let my birthday = '1988/05/18' //error |
以上兩種寫法都會出現 error。
基本上我們都是會使用駝峰命名法(camel case),也就是第二的單字開始字首都要大寫:
1 | let myBirthday = '1988/05/18' |
或是也可以使用下橫線:
1 | let my_birthday = '1988/05/18' |
以上就是今天針對變數所做的介紹,下一篇會來重新學習資料型別,預計會分成兩到三篇來介紹。