JavaScript 變數 (Variables)

變數的用途是用來儲存和讀取資料,以便進行後續的運算或流程控制,變數就像是存放資料的容器。

在現代 JavaScript (ES6+) 中,我們主要使用 letconst 來宣告變數,而傳統的 var 則逐漸被取代。

例如下面這個範例,x、y、z 都是所謂的變數:

// 使用 const 宣告一個不打算改變的變數
const x = 1;
// 使用 let 宣告一個之後可能會改變的變數
let y = 2;
// 進行運算並存入新變數
let z = x + y;

跟數學的變數和運算式是很類似的概念。

JavaScript 識別字 (Identifiers)

你取的變數名稱,像是上面例子的 x y z,我們稱做識別字 (identifier),你可以用識別字來引用某個變數。

識別字必須是唯一且不重複的,不然後面定義的新同名變數會覆蓋掉前面定義的變數。

JavaScript 識別字的命名有一定規則和限制:

  1. 識別字只允許使用字母 a-z A-Z (letters), 數字 0-9 (digits), 底線 _ (underscores) 和錢符號 $ (dollar signs)。
  2. 識別字的開頭只能是字母、底線或錢符號。
  3. 識別字是大小寫有別的 (case sensitive),例如變數 hello 不等於變數 Hello。
  4. JavaScript 的保留字 (reserved words) 不能用作變數名稱。

JavaScript 允許的字母還包含 Unicode,簡單的說中文也可以用作變數名稱,例如:

var 顏色 = '藍色';
alert(顏色);

但一般很少用中文或其他語言文字當作變數名稱。

宣告變數 (Declaring variables)

在 JavaScript 中,宣告變數的方式主要有三種:constletvar

const (常數宣告)

const 是最推薦的宣告方式,用於宣告「不會再重新賦值」的變數。這能讓你的程式碼更穩定、更好預測。

const pi = 3.14159;
const siteName = 'Fooish';

let (變數宣告)

如果你預期變數的值之後會被改變(例如迴圈中的計數器),請使用 let

let count = 0;
count = count + 1; // 允許重新賦值

var (傳統宣告)

這是舊有的宣告方式,雖然現在依然可以使用,但由於它有一些容易產生 Bug 的特性(如 Hoisting 提升和缺少區塊作用域),目前的開發實務建議盡量避免使用,改用 letconst

var oldStyle = '這是不建議的寫法';

你也可以在宣告變數的同時指定一個初始值:

let carName = 'Ferrari';

而等號 = 就是所謂的「指定運算子」(Assignment Operator),用來將右手邊的值指定給左手邊的變數。

你也可以使用逗號 , 分隔,一次宣告多個變數(但實務上推薦一行宣告一個變數,可讀性較佳):

let car1 = 'Ferrari',
  car2 = 'Lamborghini',
  car3 = 'Porsche';

變數作用域 (Variable Scope)

JavaScript 的變數有其作用的範圍,在作用範圍以外的程式碼就無法存取該變數。

根據你使用的宣告關鍵字,作用域有不同的行為:

  • var:屬於「函式作用域」(Function Scope)。
  • let / const:屬於「區塊作用域」(Block Scope),這更符合直覺且安全。

詳細的比較與說明,請參考 ES6 Block Scope let const

區域變數 vs 全域變數

依據宣告位置,我們可以分為兩類:

  1. 局部變數 (Local variables)
  2. 全域變數 (Global variables)

JavaScript 在查找變數時,會循著作用域鏈 (scope chain) 一層一層往外找,直到找到宣告的變數或找不到變數 (undefined)。

function foo() {
  // 在 function 裡面宣告的變數,作用(存在)範圍只在 function 裡面 (local)
  var carName = 'Ferrari';
  alert(carName); // 會顯示 Ferrari
}

alert(carName); // 會發生錯誤,因為找不到變數

在 function 以外的地方宣告的變數,是所謂的全域變數 (global variable),所有的 JS 程式碼都能存取到這個變數:

// carName 是一個全域變數
var carName = 'Ferrari';

function foo() {
  alert(carName); // 會顯示 Ferrari
}

alert(carName); // 會顯示 Ferrari
JavaScript 不像其他程式語言有 package level 的 scope,只有 global 或 local,所以一個 global variable 在任何地方都可以被存取到,甚至是跨不同的 JS 檔案的程式碼。所以一般會避免使用全域變數,避免全域的命名空間 (namespace) 被污染,不同檔案的同名全域變數很容易被意外互相覆蓋。

駝峰式命名 (Camel Case)

JavaScript 習慣的變數命名風格是所謂的駝峰式命名 (camel case)。

像是 firstName, lastName, carName,也就是第二個字的字母大寫。

JavaScript 保留字 (Reserved Words)

JavaScript 保留字是保留來給特殊用途或特定語法使用的,所以不能用來當作變數名稱,JavaScript 的保留字有:

break
case
catch
const
continue
debugger
default
delete
do
else
finally
for
function
if
in
instanceof
new
return
switch
this
throw
try
typeof
var
void
while
with

null
true
false

class
enum
export
extends
import
super

implements
interface
let
package
private
protected
public
static
yield