【JavaScript 筆記】運算子、型別轉換 - part 4

歡迎你點入本篇文章,本系列網頁程式設計,主要紀錄我個人自學的軌跡,另外也作為日後個人複習用。若你喜歡本篇文章,歡迎在文章底下點一顆愛心,或是追蹤我的個人公開頁~


運算子(Operator)

JS 有這些類型的運算子:

類別英文名稱運算子
算術運算子Arithmetic Operators+ - * / % ** ++ -- -(一元) +(一元)
指定運算子Assignment Operators= += -= *= /= %= **= <<= >>= &= |= ^= &&= ||= ??=
比較運算子Comparison Operators== != === !== > >= < <=
邏輯運算子Logical Operators&& || ! !! ??
位元運算子Bitwise Operators& | ^ ~ >> << >>>
三元運算子Ternary Operator? :
逗號運算子Comma Operator,
一元運算子Unary Operators+ - ++ -- delete void
關係運算子Relational Operatorsin instanceof

當中 ** 是做冪次運算,即指數運算。

那接下來我會特別寫一些比較特殊的運算子,其餘的部分在其他程式語言都算常見,就不細說了。

比較運算子

你可以發現 JavaScript 多了一個 ===,這個叫做嚴格相等運算子,因為原本的 == 是只有比較值,而在 === 就同時比較值跟資料型別是否正確。

!== 也是嚴格比較,除了比較值也比較資料型別。

範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
// == 寬鬆比較 (會做型別轉換)
console.log(5 == "5"); // true: 字串 "5" 被轉成數字 5
console.log(0 == false); // true: false 被轉成 0
console.log(null == undefined); // true

// === 嚴格比較 (不轉型別)
console.log(5 === "5"); // false: 型別不同 (number vs string)
console.log(0 === false);// false: 型別不同
console.log(null === undefined); // false

// !=, !== 同理
console.log(5 != "5"); // false: 轉型後相等,所以不等於為 false
console.log(5 !== "5"); // true: 型別不同,嚴格不相等

實務建議上,幾乎所有情況都應優先使用 === / !==,避免因隱性型別轉換造成 bug 。

邏輯運算子

!!(雙重否定)

!! 不是獨立運算子,而是兩個 ! 連用,作用是將任意值強制轉換成布林值。

1
2
3
4
5
6
7
console.log(!!1);         // true: 非零數字為 truthy
console.log(!!0); // false: 0 為 falsy
console.log(!!"hello"); // true: 非空字串為 truthy
console.log(!!""); // false: 空字串為 falsy
console.log(!!null); // false
console.log(!!undefined); // false
console.log(!![]); // true: 空陣列仍是 truthy

??(Nullish Coalescing,空值合併)

?? 只有當左側是 nullundefined 時才回傳右側的值,與 || 的差異在於:|| 對所有 falsy 值(如 0、"")都會觸發,但 ?? 不會。

1
2
3
4
5
6
7
8
9
10
11
12
13
const score = 0;
const name = "";

// 用 || 的問題: 0 和 "" 也是 falsy,會被取代
console.log(score || 100); // 100
console.log(name || "訪客"); // "訪客"

// 用 ?? 處理: 只有 null / undefined 才取右側
console.log(score ?? 100); // 0: 保留原始值
console.log(name ?? "訪客"); // "": 保留原始值

const user = null;
console.log(user ?? "預設使用者"); // null 才觸發 "預設使用者"

位元運算子

>>>(無符號右移)

>> 是有符號右移,保留正負號;>>> 是無符號右移,不管正負,最高位一律補 0,因此對負數結果差異很大。

1
2
3
4
5
6
console.log(8 >> 1);   // 4  (1000 -> 0100)
console.log(8 >>> 1); // 4 (正數結果相同)

// 負數的差異
console.log(-8 >> 1); // -4 (有符號,最高位補 1)
console.log(-8 >>> 1); // 2147483644: 最高位補 0,變成超大正整數

,(逗號運算子)

逗號運算子會依序執行每個運算式,並回傳最後一個的值,常見於 for 迴圈的初始化或更新區段。

1
2
3
4
5
6
7
8
9
10
let x = (1, 2, 3);
console.log(x); // 3: 只回傳最後一個值

// for 迴圈中同時更新多個變數
for (let i = 0, j = 10; i < 3; i++, j--) {
console.log(i, j);
// 0 10
// 1 9
// 2 8
}

一元運算子

deletevoid

  • delete 用於刪除物件的屬性。
  • void 執行一個運算式但強制回傳 undefined,常見於 <a href="void(0)"> 防止頁面跳轉。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// delete: 刪除物件屬性
const user = { name: "LukeTseng", age: 20 };
delete user.age;
console.log(user); // { name: "LukeTseng" }: age 已被刪除
console.log(user.age); // undefined

// delete 無法刪除用 const/let/var 宣告的變數
const num = 42;
console.log(delete num); // false: 刪除失敗

// void: 強制回傳 undefined
console.log(void 0); // undefined
console.log(void "hello"); // undefined
console.log(void (1 + 1)); // undefined (但 1+1 仍有被執行)

關係運算子

ininstanceof

  • in 檢查某個屬性名稱(key)是否存在於物件中。
  • instanceof 檢查某個物件是否是某個建構子(class)的實例。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// in: 檢查屬性是否存在
const car = { brand: "Toyota", year: 2023 };
console.log("brand" in car); // true
console.log("color" in car); // false
console.log(0 in [10, 20, 30]); // true: 陣列的 index 也是屬性

// instanceof: 檢查是否為某 class 的實例
class Animal {}
class Dog extends Animal {}

const d = new Dog();
console.log(d instanceof Dog); // true
console.log(d instanceof Animal); // true: 繼承鏈也算
console.log(d instanceof Array); // false

// 常見應用: 判斷錯誤類型
try {
null.property;
} catch (e) {
console.log(e instanceof TypeError); // true
}

型態轉換(Type Conversion)與強制轉型(Type Coercion)

Type Conversion(型態轉換)是由開發者主動呼叫函式來轉換型別(Explicit)。

而 Type Coercion(強制轉型)則是 JavaScript 引擎在運算時自動隱性轉換,不需要程式開發者來明確要求。

Type Conversion(顯式轉換)

1. String → Number

有三種常用方式,行為略有不同:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Number(): 嚴格轉換, 無法解析就回傳 NaN
Number("42") // 42
Number("3.14") // 3.14
Number("") // 0 <- 空字串變 0
Number(" ") // 0 <- 純空白也是 0
Number("42abc") // NaN <- 含非數字字元
Number(null) // 0
Number(undefined) // NaN

// ② parseInt() / parseFloat(): 從左往右解析,遇到非數字停止
parseInt("42abc") // 42 <- 比 Number() 寬鬆
parseInt("3.99") // 3 <- 只取整數
parseFloat("3.99px") // 3.99
parseInt("abc") // NaN

// 一元 + 運算子: 效果等同 Number(),最簡短
+"42" // 42
+"3.14" // 3.14
+"" // 0
+"abc" // NaN

:::info
註:parseInt 有第二個參數可指定進位:parseInt("ff", 16) -> 255
:::

2. Number → String

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// String()
String(42) // "42"
String(3.14) // "3.14"
String(NaN) // "NaN"
String(Infinity) // "Infinity"

// .toString(): 可指定進位
(255).toString() // "255"(十進位)
(255).toString(16) // "ff" (十六進位)
(255).toString(2) // "11111111"(二進位)

// 樣板字串 (Template Literal): 最常用
const n = 42;
`${n}` // "42"

3. Boolean → Number

true 等於 1false 等於 0,這條規則在 Coercion 時很重要 :

1
2
3
4
5
6
7
Number(true)   // 1
Number(false) // 0

// 實際應用: 統計陣列中 true 的數量
const results = [true, false, true, true, false];
const count = results.reduce((sum, val) => sum + Number(val), 0);
console.log(count); // 3

4. Boolean → String

1
2
3
4
5
6
String(true)   // "true"
String(false) // "false"

// Boolean("false") 不會得到 false
Boolean("false") // true: 非空字串永遠是 truthy
Boolean("") // false: 只有空字串才是 false

Type Coercion(隱式強制轉型)

1. String + Number

+ 運算子具有字串串接的功能,只要其中一方是字串,另一方就會被強制轉成字串:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
"5" + 3      // "53": 3 被轉成 "3" 再串接
"5" + true // "5true"
"5" + null // "5null"
"5" + undefined // "5undefined"

// 其他運算子 (-, *, /) 沒有字串模式,會把字串轉成數字
"10" - 3 // 7: "10" 被轉成 10
"6" * "2" // 12
"10" / "2" // 5
"abc" - 1 // NaN

// 連鎖陷阱:
1 + 2 + "3" // "33": 先算 1+2=3,再 3+"3"="33"
"1" + 2 + 3 // "123": 先算 "1"+2="12",再 "12"+3="123"

2. Boolean + Number

Boolean 在數學運算中會先被轉成 01

1
2
3
4
5
6
7
8
true + 1    // 2  (true -> 1)
false + 1 // 1 (false -> 0)
true + true // 2
true * 5 // 5
false * 99 // 0

// 陷阱
true + "1" // "true1": + 有字串時,boolean 先轉字串

3. Comparison of Different Types

== 比較時的型別轉換規則:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 規則: Number 優先,先把對方轉成 Number 再比
"5" == 5 // true ("5" → 5)
true == 1 // true (true → 1)
false == 0 // true (false → 0)
null == 0 // false: 例外,null 只等於 undefined
null == undefined // true: 唯一的例外組合
null == false // false

// 一些陷阱
"0" == false // true (兩邊都轉成 0)
"" == false // true (兩邊都轉成 0)
[] == false // true ([] -> "" -> 0,false -> 0)
[] == ![] // true (兩邊都變 0)

4. Boolean Context

當 JavaScript 需要一個布林值時(如 ifwhile? :),會自動將值判斷為 truthyfalsy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Falsy 值
if (false) { }
if (0) { }
if ("") { }
if (null) { }
if (undefined) { }
if (NaN) { }

// Truthy 陷阱 (容易誤判為 false)
if ([]) { console.log("空陣列是 truthy!") }
if ({}) { console.log("空物件是 truthy!") }
if ("0") { console.log('"0" 是 truthy!') }
if (-1) { console.log("負數是 truthy!") }

// 實際應用: 安全取值
const username = "";
if (username) {
console.log(`Hi, ${username}`);
} else {
console.log("請輸入使用者名稱"); // 空字串為 falsy,因此進到這
}

總整理

運算子(Operators)

1. 比較運算子:嚴格 vs 寬鬆

  • === / !==(嚴格):同時比較資料型別,避免隱性轉型 bug。
  • == / !=(寬鬆):只比較值,型別不同會先自動轉型再比較。

2. 邏輯運算子

  • !!(雙重否定):非獨立運算子,用來將任意值強制轉為布林值(例如:!!1 變成 true)。
  • ??(空值合併):僅當左側為 nullundefined 時,才回傳右側值。
    • || 的差異:|| 遇到 0""(空字串)也會觸發右側;?? 則會保留 0"",適合用於設定預設值。

3. 特殊用途運算子

  • >>>(無符號右移):不管正負,最高位一律補 0。若是負數,結果會變成極大的正整數。
  • ,(逗號):依序執行並只回傳最後一個值。常用於 for 迴圈一次更新多個變數(i++, j--)。
  • delete:專門用來刪除物件屬性(無法刪除用 var/let/const 宣告的變數)。
  • void:執行運算式但強制回傳 undefined(常見應用:<a href="void(0)"> 防跳轉)。

4. 關係運算子

  • in:檢查屬性(Key)或陣列索引是否存在於物件/陣列中。
  • instanceof:檢查物件是否為某 Class 或建構子的實例(會追溯繼承鏈)。

型態轉換(Conversion vs Coercion)

  • Conversion(顯式轉換):開發者主動寫 Code 轉換。
  • Coercion(隱式轉型):JS 引擎在運算時自動轉換。

1. 顯式轉換 (Explicit Conversion)

  • 轉 Number:
    • Number() / +:嚴格,有非數字字元就給 NaN+ 是最簡短寫法,如 +"42")。
    • parseInt() / parseFloat():寬鬆,由左至右解析,遇到非數字才停止。
  • 轉 String:
    • String(值).toString(進位制)
    • 樣板字串 `` 。
  • 轉 Boolean 陷阱:
    • true 轉數字為 1false0
    • Boolean("false") 結果是 true(因為它是一串非空字串)。

2. 隱式轉型 (Implicit Coercion)

  • 數學運算的自動轉型:
    • 遇到 +:只要有一方是字串,另一方就會變成字串並串接(例:"5" + 1 = "51")。
    • 其他運算(- * /):沒有字串模式,會強迫將字串轉成數字來算(例:"10" - 3 = 7)。
  • == 比較的轉型規則:
    • 偏好轉成 Number 互相比較(例:"5" == 5true == 1 皆為 true)。
    • 極端例外:null 只和 undefined 相等,不等於 0false
  • 布林情境(if / while / 三元):
    系統會自動判斷值為 Truthy (真值) 或 Falsy (假值)。
    • Falsy:false, 0, "" (空字串), null, undefined, NaN
    • Truthy(易錯陷阱):除了上述 6 個,其他全是 Truthy:[](空陣列), {}(空物件), "0", -1

參考資料

JavaScript Bitwise Operators - GeeksforGeeks

JavaScript Logical Operators - GeeksforGeeks

JavaScript Comparison Operators - GeeksforGeeks

JavaScript Arithmetic Operators - GeeksforGeeks

JavaScript Assignment Operators - GeeksforGeeks

JavaScript Operators - GeeksforGeeks

How is == Different from === in JavaScript? Strict vs Loose Equality Explained

Nullish coalescing operator (??) - JavaScript

Type Conversion and Type Coercion in JavaScript - GeeksforGeeks