iT邦幫忙

2023 iThome 鐵人賽

DAY 2
0
自我挑戰組

重新複習JavaScript系列 第 2

[Day -2] 變數(variable)

  • 分享至 

  • xImage
  •  

在學習JavaScript的人在查找資料時一定都會看到 varletconst這些宣告變數的方式,為什麼宣告變數會有這麼多方式呢,以下就讓我們來好好的了解一下這三種宣告方式的差異點吧

變數

在說到他們間的差異時,先來複習一下什麼是變數。

變數就是我們用來儲存資料的基本單位。

就像我們在搬家時,都會在紙箱上面寫上這箱裡面裝的是什麼,這樣我們在之後整理東西就會比較迅速;而變數就像是那個有寫名字的紙箱,用來存放我們想要存放的資料。

在命名變數的名稱的時候,我們會讓變數是一個有意義的名稱,來提高程式碼的可讀性。另外我們在命名時還要避開JavaScript保留字 (Reserved Words) 與關鍵字 (keyword)。

下面是一段宣告變數的程式碼:

let myBirthday = '1988/05/18'

讓我們看到 let=myBirthday ,他們三個分別對應到的是對變數的宣告(declare)、指派(assign)與命名慣例(naming convention),接下來我們就照著這三個分類來做解釋。

宣告(declare)

ES6前的時代

在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衍伸出下列狀況:

  1. 全域變數: 使用 var 宣告的變數在全域作用域內都可見,這可能導致變數名稱衝突,特別是在多個 JavaScript 檔案中。
  2. 重複宣告: 在同一作用域內重複使用 var 宣告同一個變數,不會引發錯誤,而是視為同一個變數,可能導致錯誤的邏輯。
  3. 無 block scope: var 宣告的變數無法在區塊(例如 iffor)內建立新的作用域,這可能導致意外的變數共享和作用域問題。

scope 跟 hoisting 詳細的說明我會後面在做解釋(主要是講下去整篇會太長,而且scope跟hoisting蠻適合拉出來說,之後要複習也方便)

ES6時代

ES6發布之後,JavaScript有了區塊域(block)的概念,因此我們捨棄了無法在block內設立新的scope的var ,取代它的就是 letconst

let、const特性

  • 區塊作用域(block scope)
  • 變數會提升,但若未宣告該變數時,就去提取該變數便會報錯,而非回傳undefined
  • 不允許重複宣告
  • 全域變數不會成為window的屬性

當我們使用 let 關鍵字宣告變數時,代表我們預期資料是可以被改變的。

let相反,當我們使用 const 來宣告時,我們預期這組資料不能被改變,也就是常數(constant)的概念。

區塊作用域(block scope)

區塊作用域指的就是大括號{}之間的區域,這個時候變數就只存活在{}這個括號裡,{}外就不能調用。

我們來看一個非常簡單的例子:

{
    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();

變數提升,但若未宣告該變數,會回傳錯誤,而非undefined

使用letconstvar來宣告變數,都會提升至作用域的最高處。不同的是,如果我們沒有宣告就直接使用該變數時,var會回傳預設值undefined,但constlet會報錯。

不允許重複宣告

如果該變數已經被宣告過,就不能再宣告。letconst都一樣。

let food = 'apple';
let food = 'egg'; 

//SyntaxError: Identifier 'food' has already been declared

全域變數會不會成為window的屬性

var宣告全域變數,會成為window的屬性,但letconst不會。

指派(assign)

在第一次接觸變數的賦值時,我一直是把=看作是等於 ,但越學越覺得有點奇怪。

首先,讓我們把最一開始那段程式碼拆解一下:

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這個變數。

命名慣例(naming convention)

在 JavaScript 中,我們在為變數命名時,需要注意以下幾點:

特殊符號

可以使用錢符 $、底線 _當成首字。如 $myBirthday_myBirthday

大小寫

在 JavaScript 裡,大小寫是有區分的,像是 MyBirthday 與 myBirthday 會被視作不同變數。

JavaScript 的保留字

在前面有提到,JavaScript 會有一些字作為特定的用途,而這些單字就不能拿來做為變數的名稱。

不能用數字開頭

數字不能作為變數開頭。

兩個單字使用camelCase 命名法

前面有提到讓變數是一個有意義的名稱,來提高程式碼的可讀性

因此在變數的命名上有時候我們就會有兩個單字,但如果我們這樣寫:

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'

以上就是今天針對變數所做的介紹,下一篇會來重新學習資料型別,預計會分成兩到三篇來介紹。


上一篇
[Day -1] 鐵人賽參賽前言
下一篇
[Day -3] 作用域(scope)
系列文
重新複習JavaScript30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言