前言
和小夥伴討論到 implicit coercion 來研究研究
一開始討論到 為啥String前面 加上 一個 +
JS 就會幫你轉成Number
神奇神奇
來個例子
1 |
|
輸出是 1245
- 前面+會讓把type轉成number
酷!!!
JavaScript 的型別不在於變數本身,而在於變數被賦予的值。
找了資料才發現叫做 :「強制轉型」(coercion)
「強制轉型」有兩種
隱含的強制轉型 —
implicit coercion
明確的強制傳型 —
explicit coercion
隱含的強制轉型 — implicit coercion
JavaScript 在運算的時候,如果看到兩個不同型別的值,就會自動判斷,把值轉換為相同型別,再做運算。
舉個例子:
1 | let a = "1"; //字串 |
以上這些就是 JavaScript 變數的「強制轉型
」,
而且是 JavaScript 親切的、自動的、在背後運作的、「**隱含的強制轉型
**」( implicit coercion )。
一下變字串
,一下有變成數字
、一下變成布林值
。
「隱含的轉型」( implicit coercion )基本上可以轉成三種型別:
- 自動轉換為布林值( ToBoolean )
- 自動轉換為數值( ToNumber )
- 自動轉換為字串( ToString )
四則運算時的強制轉型
JavaScript在做四則運算的時候跟小學課本教的一樣,由左而右「先乘除後加減」。
其中以加法(+)最需要注意!
如果是數值的運算,那沒有轉型的問題。「字串」的相加也沒有轉型的問題。
1 | var x = 1 + 2; |
只有在 不同型別
的狀況下才有轉型的問題:
當加號
+
兩側有一個是字串的情形下,會將「非字串
」的那一邊「自動轉型」為字串
,再將兩個字串連接在一起。- 如果另一方為
number
、boolean
、object
的情況下,number
、boolean
、object
會去叫用它們的 ***.toString 「原型方法」
**,把自己變成 **字串
**,再去和另一個字串
組合。
- 如果另一方為
當一邊是
數字
,一邊是undefined
的時候,undefined
會被試著轉為數字
,變成NaN
,任何數字
與NaN
相加都是NaN
。當一邊是
數字
,加號另一邊是null
的時候,null
會被轉為數字0
。
1 | //數字與字串相加 |
而如果是減乘除法( - * / )的情況,除了數值以外的其他基本型別都會透過 Number() 方法轉為數字。物件則在乘除的時候會透過 Number() 方法,轉為數字,在減法時透過 valueOf() 方法轉為數字。
1 | 49 - '36' //13 |
下面附上變數在四則運算時的「自動轉型」規則:
四則運算 | 數字 | 基本型別非數字 | 物件 |
---|---|---|---|
減法 | 正常運算 | Number()方法轉為數字 | 透過valueOf()轉為數字 |
乘法 | 正常運算 | Number()方法轉為數字 | Number()方法轉為數字 |
除法 | 正常運算 | Number()方法轉為數字 | Number()方法轉為數字 |
加法 | 正常運算 | 如果是number、boolean透過toString()方法轉為字串, null或undefined透過String()轉為字串 |
toString()轉為字串 |
比較運算子的強制轉型
比較運算子用來比較兩側的數值,比較之後得到布林值 true 或 false。
一個等號 =
,我們知道是「指定、賦值」的意思。
1 | var x = 49; //X 的值 =49 |
==
是相等
的意思,而 ===
是全等
的意思。
1 | var x = 49; //數字 |
使用 ==
相等的時候,會
自動替兩側的變數
轉型。
當使用===
全等的時候,不會
替變數自動轉型,是比較嚴謹
的模式,也是比較推薦使用的方法。
比較特別的是,NaN
不等於NaN
,不管是 ==
還是 ===
,
都是一樣 NaN
不等於 NaN
。
==的自動轉型規則
- 當遇到「
字串
」與「數字
」做比較的時候,
字串會透過Number()
嘗試轉為數字
,再進行比較。 - 如果比較的一方為
布林值
,則true
會轉為1
,false
會轉為0
。 - 當== 的一側為
物件型別
,另一側為基本型別
,
物件型別會透過valueOf()
,轉為對應的基本型別
進行比較。
不等於!= 與 !==
!=
與「! ==
」兩者都是不等於
,
但是 !=
會
替變數做自動轉型
,
而 !==
不會
替變數自動轉型
,推薦使用 !==
大於>與小於<的強制轉型
有看到一個數字比大小的有趣例子,借來筆記一下:
1 | console.log(1 < 2 < 3); // true |
天哪!怎麼會是這樣的結果! 3 < 2 < 1 的布林值竟然是 true
其實是因為 < 是由左向右( left to right )去做比較,下面來解釋一下:
1 | console.log(1 < 2 < 3); |
所以才會得出 console.log( 3 < 2 < 1 );會變成 true 的結果。
Boolean的強制傳型
邏輯運算子( Logical Operator )有 AND &&
、 OR ||
、NOT !
三種。
運算子兩側的值經過 ToBoolean 轉換後會得到一個布林值,再由邏輯運算子比較後傳回其中一個值。
&&
以及 ||
進行判斷時,會對左邊
的數值進行檢查,如果原本是布林值,就進行後續判斷。
如果不是,則透過 ToBoolean 轉換為 true 或 false 。
AND && :(條件/運算式 A ) && (條件/運算式 B ),
如果兩側的值都為 true ,得到 true 的結果;
如果其中一方為 false ,則得到 false 。
如果第一個值轉換為true,則回傳第二個值,否則回傳第一個值。OR :(條件/運算式A) (條件/運算式B),
兩側的值只要有一側為 true ,就得到 true 的結果;
如果兩側都為 false ,才得到 false 。
如果第一個值轉換為true,則回傳第一個值,否則回傳第二個值。NOT ! : true 的結果透過 ! 轉換會得到 false ,而 false 的結果會變成 true。
那些經過ToBoolean轉換後會得到true的狀況太多,而會得到false的值只有以下五種:
undefined
Null
+0、-0
NaN
空字串""或’’
其他的值都會轉為true。
明確的強制傳型(explicit coercion)
也就是透過JavaScript提供的函式來進行變數型別轉換,例如:
- 轉換為數值型別:
Number()
、parseInt()
、parseFloat()
- 轉換為字串型別:
toString()
、String()
- 轉換為布林型別:
Boolean()
Number()、parseInt()、parseFloat()
Number()可以將值「嘗試轉型」為「數值型別」,但要並非每種物件都可以順利轉成 number 型別,如果轉型失敗就會變成 NaN (非數值的數值)!
parseInt(str [, radix]) 函式能將輸入的字串轉成整數,第二個參數 radix 代表使用哪種進位制轉換。
它會忽略前後空白,在遇到字元被無法解析時,會忽略那個字元與後面的所有字元,停止解析,並回傳目前為止的結果。
如果第一個字元就無法被解析,會回傳 NaN。
parseFloat(str)能將字串轉換為以十進位表示的浮點數。
來看一下範例:
1 | Number('123'); //123 |
.toString()、String()
String() 與 .toString() 都可以將值轉換為字串型別,
差別在於 .toString() 在收到 null
、 undefined
和數字
時會報錯。
1 | String(123) //'123' |
Boolean()
Boolean() 可以用來將其他的資料型態轉型成布林值型態。
還記得前面提過幾種會變成
false
的值嗎?
1 | Boolean(100) //true |
結論
重點整理一下,如果可以掌握一些概念,之後還可以再仔細琢磨:
強制轉型分為兩種
隱含的強制轉型:就是 JavaScript 在運算的過程中,依照它的規則在背地裡把值的型別轉換成其他類的型別。
- 四則運算中加法如果遇到「字串」的轉型最需要留意,其他的減乘除都會試圖轉換成數字來處理。
- 使用「===」相等的時候,會自動替兩側的變數轉型。當使用「===」全等的時候,不會替變數自動轉型,建議使用「===」來進行比較。
- 在布林值的轉型部分,請記得: undefined 、 Null 、 +0 、 -0 、 NaN 、空字串都會轉換成 false。
明顯的強制轉型:透過 JavaScript 提供的函式來進行變數型別轉換。
- 轉換為數值型別: Number() 、 parseInt() 、 parseFloat()
- 轉換為字串型別: toString() 、 String()
- 轉換為布林型別: Boolean()
References
- ㄟ問你喔,強制轉型是什麼?轉換型別有規則可循嗎?(數字型別篇)
- ㄟ問你喔,強制轉型是什麼?轉換型別有規則可循嗎?(布林值、字串篇)
- 何謂強制轉型、以及如何作到轉換型別?
- [教學]何謂強制轉型、以及如何作到轉換型別?
- 你懂 JavaScript 嗎?#8 強制轉型(Coercion)
- JavaScript 全攻略:克服 JS 的奇怪部分
- Javascript型別轉換的技巧
- JavaScript資料型別轉換
- JS 紀錄2 - 包裹物件、自動轉型
- 認識 parseInt、parseFloat 與 Number 轉換成數字的三種方法
- 前端工程研究:關於 JavaScript 中 Number 型別的常見地雷與建議作法