---
# System prepended metadata

title: '[JavaScript] 何謂強制轉型、以及如何作到轉換型別？'
tags: [前端筆記]

---

# [JavaScript] 何謂強制轉型、以及如何作到轉換型別？
###### tags: `前端筆記`
## 總結
1. 沒有特別原因的話，一般相等（兩個=）先不要，請使用嚴格相等（三個=）JavaScript 才不會自動轉型
2. 如何做到轉換型別？
   - 自己下指令代碼 => 如 `Boolean()`, `String()`, `Number()`, `parseInt()` 等等
   - JavaScript 自己轉（建議不要，因為有時候會出現意想不到的錯誤）
## 強制轉型有兩種：
### 1. 明確的（explicit）的轉型
也就是有下代碼給 JavaScript，明明確確地說我要資料轉型態！
#### 1. 轉字串（string）
```javascript=
String(123); // '123'
```
#### 2. 轉數字（number）
- 用 `Number()`
```javascript=
Number('123'); // 123
Number('  123123123   '); // 123123123
Number(' 12313213231231hhhhh'); // NaN
Number(' 12313213231231hhhhh1232123132'); // NaN
Number('aaa'); // NaN
Number('12 213'); // NaN
```
- 用 `parseInt()`
```javascript=
parseInt('123'); // 123
parseInt('  123123123   ');
parseInt(' 12313213231231hhhhh');
parseInt(' 12313213231231hhhhh1232123132'); // 12313213231231
parseInt('aa'); // NaN
parseInt('12 213'); // 12
```

##### `Number()` 跟 `parseInt()` 差別在哪裡？
由上面的例子可以看出，兩個都會先自動執行 `trim()` 把頭尾的空白濾掉，而且遇到不行的情況就會吐 `NaN`。
但是當 `Number()` 遇到真字串（也就肉眼看也不是數字）時就會覺得參數全部是真字串，即便裡面確實有數字（但是型別是字串）， `Number()` 還是會吐 `NaN`。但是 `parseInt()` 遇到真字串時就會停止，並吐出目前成功轉型的數字。另外，如果在參數中出現「空白」時 `Number()` 會回傳 `NaN`，但是在 `parseInt()` 則就停止執行，只會吐出前面轉出來的數字。

##### 那麼要如何讓 `parseInt()` 遇到空白繼續轉呢？
=> 因為裡面的參數（也就是 `String`）裡面有空白，所以造成 `parseInt()` 停止繼續轉，所以就想辦法刪掉參數的空白！
刪除字串中的空白（[ref.](https://1loc.dev/string/remove-spaces-from-a-string/)）
```javascript=
const removeSpaces = (str) => str.replace(/\s/g, '');
// 搭配 parseInt()
parseInt(str.replace(/\s/g, ''));
parseInt('1231231  22 '.replace(/\s/g, ''));
// 123123122
```
*str.replace()可以輸入 `RegExp` 的物件或文字，範例中的解法就是使用 `RegExp` 但目前對這個還沒研究 QQ*

值得注意的是 `Number()` 跟 `parseInt()` 在特定的參數時會出現不同的結果（[ref.](https://thisthat.dev/number-constructor-vs-parse-int/)）：

```javascript=
parseInt(); // NaN
parseInt(null); // NaN
parseInt(true); // NaN
parseInt(''); // NaN

Number(); // 0
Number(null); // 0
Number(true); // 1
Number(''); // 0
```

*parseInt() 其實可以下第二個參數，但是我覺得我現在用不到就沒多研究。*

#### 3. 轉 Boolean
只要記得以下 falsy value 就好了，因為除了這些 `Boolean()` 都會是 `true`。
```javascript=
Boolean('')           // false
Boolean(0)            // false     
Boolean(-0)           // false
Boolean(NaN)          // false
Boolean(null)         // false
Boolean(undefined)    // false
Boolean(false)        // false

// 所以
Boolean('false') // 是 true 喔
Boolean({})             // true => 空「字串」才是 falsy
Boolean([])             // true => 同上
Boolean(Symbol())       // true
!!Symbol()              // true
Boolean(function() {})  // true => 空 function 也不屬於 falsy value
```
### 2. 不明確的（implicit）的轉型，可以想成是 JavaScript 貼心地自動轉型
不明確的轉型 = 沒下代碼告知 JavaScript 我要轉型，但是 JavaScript 卻自己幫忙轉型了。
不明確的轉型就比較奇怪一點了，也因為奇怪的緣故，所以強烈建議在對待型別上就多花點心使用嚴格相等（===），或者在進行運算以前留意型別，先自己寫代碼轉成對應的資料型別（比方來說要求加法的和，就要先寫代碼確保是 Number + Number）。
#### 1. 使用 `+` 但是 `+` 的其中一方為字串（string）時
兩個數字（number）相加時是一般的數學加法運算，但是如果相加的兩方其中一方為字串，JavaScript 則會貼心地使用字串運算子。
```javascript=
1 + 1; // 2
1 + '1'; // '11'

// 想要正常的數字加法
1 + parseInt('1', 10);  // 2
```
#### 2. 其餘的算數運算符就會讓「字串」強制轉型
不像上方的 `+` 的例子，如果其中一方為字串就會判斷是字串運算字。在其他的數學運算符中則是會先用 `Number()` 強制讓字串的那方轉為數字才運算。

*`Number()` 如果發現字串轉不成數字時會回傳 `NaN`。這裡有[規則表](https://es5.github.io/#x9.3)，不確定之後可以回來看。*

```javascript=
'10' / 2; // 5
// => Number('10') / 2

'10' * '10'; // 100
// => Number('10') * Number('10')

' a' * 10; // NaN
// => Number(' a') * 10
```

#### 3. 比較運算子也會觸發轉型
>除了嚴格相等（=*3）以及嚴格不相等（!==）不會自動轉型之外，其他的都會自動轉型成數字（Number）再比較

```javascript=
123 != '456'  // true
// => 123 != Number('456')
4 > '5'      // false
// => 4 > Number('5')
5 / null    // Infinity
// 這邊會得到特例 Infinity
3 >= '3'    // true
// 3 >= Number('3')
true == 'true'  // false
// Number(true) == Number('true') 
// => 1 == NaN
!!'false' == !!'true' // true
// 'false' 跟 'true' 都為字串（string），! 會把後面的型別轉為 Boolean，切記，字串的話只有空字串為 false，其餘都是 true
// 實際步驟：
// 1. !!'false' == !!'true'
// 2. !false == !false
// 3. true == true => true
```
`||` 及 `&&`
`||(or)`：由左到右判斷，當左邊被強制轉為 Boolean 時為 true 時則回傳左邊的運算元；反之若為 false，則回傳第二個運算元
`&&（and）`：一樣由左至右判斷，但當左邊被強制轉為 Boolean 為 true 時則是回傳右邊的運算元；反之回傳左邊的運算元
```javascript=
const a = true || false;  // true
const b = true && false;  // false
0 || "0" && {}  // {}
// 1. (0 || "0") && {}
// 2. (false || true) && true
// 3. true && true
// 4. {}
```
#### 4. `if...else`, `for loop`, `while loop` 中的條件句也會偷偷轉 Bolean
```javascript=
let i = 4;
if (i) {
// if (Boolean(4)) { statement ...} 
  console.log('Hi');
}
// 'Hi'

```

#### 如果是 `object` + `object` 或是 `array` + `array` 呢？
==兩個物件（或兩個陣列）彼此相加並不會產生額外的物件（或陣列）==
下面的解釋我覺得很少會用到，所以有黃底的概念就好。

1. 如果目前情況被 JavaScript 判別字串的話則先用 `toString()` 才會用 `valueOf()`
2. 如果目前情況被 JavaScript 判別數字的話則先用 `valueOf()` 才會用 `toString()`
`toString()` 及 `valueOf()` 會回傳基本型態的值（primitive value），但如果回傳的是原本的物件，那麼 JavaScript 就會無視，當作改完了。

```javascript=
[1] + [2]; // '12'
[1, 2, 3] + [2, 2, 3];  // '1,2,32,2,3' 
{name: 'Tim'} + {name: 'Tom'}; // '[object Object][object Object]'

let user = {name: "John"};

alert(user); // [object Object]
alert(user.valueOf() === user); // true
user.valueOf(); // {name: 'John'} 如果回傳原本的物件就會當作改完了
```

#### 其他的範例([ref.](https://cythilya.github.io/2018/10/15/coercion/#%E9%9A%B1%E5%90%AB%E7%9A%84%E5%BC%B7%E5%88%B6%E8%BD%89%E5%9E%8Bimplicit-coercion))

```javascript=
'0' == false; // true
// => Number('0') == Number(false)

false == 0; // true
// => Number(false) == 0

false == ''; // true
// false == Boolean('')

false == []; // false
// false == Boolean([])

false == {}; // false
// false == Boolean([{})

'' == 0; // true
// Number('') == 0

'' == []; // true
// Number('') == [].toString()
// Number('') == Number('')

'' == {}; // false
// 字串轉數字，空物件

0 == []; // true
// 0 == 陣列 toString() 得到 '' 再轉數字

0 == {}; // false
// {} 得到空物件

[] == ![]; // true
// 左手邊取 valueOf 得到空字串再轉數字得到 0，右手邊被 ! 強制轉為布林得到 false 再轉為數字

2 == [2]; // true
// 陣列取出變字串再轉數字

'' == [null]; // true
// 陣列取 toString 得到空字串，轉數字後得到 0
0 == '\n'; // true
// ’\n’ 意即 ‘ ‘（空白），轉數字後得到 0
```

## 參考資料
1. [你懂 JavaScript 嗎？#8 強制轉型（Coercion）](https://cythilya.github.io/2018/10/15/coercion/#%E9%82%8A%E7%B7%A3%E6%83%85%E6%B3%81)
2. [JavaScript-Equality-Table](https://dorey.github.io/JavaScript-Equality-Table/)
3. [JavaScript type coercion explained](https://www.freecodecamp.org/news/js-type-coercion-explained-27ba3d9a2839/)
4. [JS 原力覺醒 Day010 - 自動轉型 （Coercion）](https://ithelp.ithome.com.tw/articles/10220471)
5. [Object to primitive conversion](https://javascript.info/object-toprimitive)
6. [Why does "true" == true show false in JavaScript?](https://stackoverflow.com/questions/11363659/why-does-true-true-show-false-in-javascript)

