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