今天是JavaScript學習紀錄的Day2!
在介紹完環境與框架後,我們要進一步認識「變數」跟「型別」~![]()
今日的目標:
變數是什麼呢?
其實變數就是幫一段資料取名字,在 JavaScript 的歷史裡,宣告變數有三種方式:var、let、const。
我們會用他來「存放資料」,就像是個命名好的「箱子」,裡面可以裝任何東西,
這些資料可以放進去、拿出來、改掉或固定。
但要注意的是,不是所有「箱子」都可以接受這些更動喔!
我們可以把他們想像成是有不同脾氣的「箱子」,最主要的差異在於「作用域」與「是否可重新賦值」。
var:舊時代的變數宣告
宣告在函式內:在「區塊 {}」外也有效
if (true) {
var x = 10;
}
console.log(x); // 10,因為var不是區塊作用域,在「區塊 {}」外也有效。
宣告在函式外:變成全域變數,會掛到 window 物件上(這就是全域變數)。
var a = 1;
console.log(window.a); // 1
let:區塊級變數
宣告在函式內:只在宣告所在的「區塊 {}」中有效
if (true) {
let y = 20;
}
console.log(y); // ReferenceError,因為 y 只存在 if 區塊內
宣告在函式外:
雖然像「全域變數」一樣也能在整個檔案裡使用,但並不等於「全域變數」喔!它是會被定義在外層作用域,不會掛到 window 物件上。
let b = 2;
console.log(window.b); // undefined
const:不可變常數
正確
const pi = 3.14159; // 有賦值
錯誤
const x; // SyntaxError: Missing initializer in const declaration
const PI = 3.14159;
PI = 3.25; // TypeError:不能重新指定
const fruits = ["apple", "banana"];
fruits.push("mango"); // 可以改內容
// fruits = ["pear"]; 不能把陣列整個換掉
| 變數 | 是否可重新賦值 | 是否可重複宣告 | 作用域 (Scope) |
|---|---|---|---|
| var | ✅ | ✅ | 函式作用域 (Function Scope) |
| let | ✅ | ❌ | 區塊作用域 (Block Scope) |
| const | ❌ | ❌ | 區塊作用域 (Block Scope) |
通常我們在程式執行前會先宣告變數,但如果我們先執行程式再宣告變數,就會造成「變數提升」!
「變數提升」意思是:變數宣告會在程式執行前被搬到作用域頂端,這就是「提升」。
但要注意的是,不同的宣告方式行為不同。
var 的變數提升
console.log(a); // undefined
var a = 10;
var a; // 宣告被提升+初始化undefined
console.log(a);
a = 10; // 賦值留在原地
let / const 的提升
console.log(b); // ReferenceError
let b = 20;
暫時性死區(TDZ, Temporal Dead Zone)
{
console.log(x); // ReferenceError
let x = 5;
console.log(x); // 5
}
綜合變數提升與TDZ概念,以上這段程式我們可以這樣理解~
程式編譯階段:
JavaScript 引擎已經「看見」let x 這個宣告,只做「宣告提升」,但不初始化。
所以在這個 block 裡,x 變數已經存在,但還在 TDZ。
程式執行階段 (runtime):
跑到第一行 console.log(x) 時嘗試存取 x,但它還在 TDZ → ReferenceError。
當執行到 let x = 10 這一行 → 引擎才真正初始化變數,x 綁定到 10。
之後再呼叫 console.log(x); → 印出 10。
| 關鍵字 | 提升 (Hoisting) | 初始化 | TDZ 是否存在 |
|---|---|---|---|
| var | 提升宣告 + 初始化 undefined | undefined | ❌ |
| let | 只提升宣告,不初始化 | 無 | ✅ |
| const | 只提升宣告,不初始化 | 無 | ✅ |
根據 ECMAScript 標準,JavaScript 共有 7 種原始型別 (Primitive Types),再加上一個 Object:
let isStudent = true; // Boolean
let empty = null; // Null
let notSet; // Undefined
let big = 123456789n; // BigInt
let id = Symbol("uid"); // Symbol
let name = "小明"; // String
let age = 18; // Number
let person = { name: "小明", age: 18 };
let hobbies = ["coding", "music"];
今天結束了!明天的 Day 3,我們就要讓這些資料真正動起來囉~![]()