何謂強制轉型、以及如何作到轉換型別?
我們都知道JavaScript的基本型別有以下幾種:
- String :字串,由一連串的字符 (characters) 組成。
- Number :數值,為 floating point number。
- Boolean :true 或 false。
- undefined :表示現在還沒有給值。
- null :不知道之前有沒有值,但是現在沒有值。
- Symbol :ES6 出現的新型別。
JavaScript 的型別不在於變數本身,而在於變數被賦予的值。
如果以上那些你都知道,那你該來看看JavaScript變態的部分—「強制轉型」( coercion )。
斯斯有兩種,「強制轉型」也有兩種:
- 隱含的強制轉型 — implicit coercion
- 明確的強制傳型(explicit coercion)
隱含的強制轉型 — implicit coercion
剛剛提到 JavaScript 的型別不在於變數本身,而在於變數被賦予的值。
JavaScript 在運算的時候,如果看到兩個不同型別的值,就會自動判斷,把值轉換為相同型別,再做運算。很親切(變態)吧!!??
不多說,讓我們看一下例子,比較容易進入狀況:
以上這些「我變我變我變變變」的情形就是 JavaScript 變數的「強制轉型」,而且是 JavaScript 親切的、自動的、在背後運作的、「隱含的強制轉型」( implicit coercion )。一下變字串,一下有變成數字、一下變成布林值…比孫悟空72變還厲害。
這種「隱含的轉型」( implicit coercion )基本上可以轉成三種型別:
- 自動轉換為布林值( ToBoolean )
- 自動轉換為數值( ToNumber )
- 自動轉換為字串( ToString )
四則運算時的強制轉型
JavaScript在做四則運算的時候跟小學課本教的一樣,由左而右「先乘除後加減」。
其中以加法(+)最需要注意!
如果是數值的運算,那沒有轉型的問題。「字串」的相加也沒有轉型的問題。
只有在不同型別的狀況下才有轉型的問題:
- 當加號 + 兩側有一個是字串的情形下,會將「非字串」的那一邊「自動轉型」為字串,再將兩個字串連接在一起。如果另一方為 number 、 boolean 、 object 的情況下, number 、 boolean 、 object 會去叫用它們的** .toString 「原型方法」**,把自己變成字串,再去和另一個字串組合。
- 當一邊是數字,一邊是 undefined 的時候, undefined 會被試著轉為數字,變成 NaN ,任何數字與 NaN 相加都是 NaN 。
- 當一邊是數字,加號另一邊是 null 的時候, null 會被轉為數字 0 。
而如果是減乘除法( - * / )的情況,除了數值以外的其他基本型別都會透過 Number() 方法轉為數字。物件則在乘除的時候會透過 Number() 方法,轉為數字,在減法時透過 valueOf() 方法轉為數字。
下面附上變數在四則運算時的「自動轉型」規則:
四則運算 | 數字 | 基本型別非數字 | 物件 |
---|---|---|---|
減法 | 正常運算 | Number()方法轉為數字 | 透過valueOf()轉為數字 |
乘法 | 正常運算 | Number()方法轉為數字 | Number()方法轉為數字 |
除法 | 正常運算 | Number()方法轉為數字 | Number()方法轉為數字 |
加法 | 正常運算 | 如果是number、boolean透過toString()方法轉為字串,null或undefined透過String()轉為字串 | toString()轉為字串 |
比較運算子的強制轉型
比較運算子用來比較兩側的數值,比較之後得到布林值 true 或 false。
一個等號 =,我們知道是「指定、賦值」的意思。
在JavaScript中, ==
是相等的意思,而 ===
是全等的意思。
使用 ==
相等的時候,會自動替兩側的變數轉型。
當使用 ===
全等的時候,不會替變數自動轉型,是比較嚴謹的模式,也是比較推薦使用的方法。
比較特別的是,NaN不等於NaN,不管是 ==
還是 ===
,都是一樣 NaN 不等於 NaN 。
==的自動轉型規則:
- 當遇到「字串」與「數字」做比較的時候,字串會透過 Number() 嘗試轉為數字,再進行比較。
- 如果比較的一方為布林值,則 true 會轉為 1 , false 會轉為 0 。
- 當
==
的一側為物件型別,另一側為基本型別,物件型別會透過 valueOf() ,轉為對應的基本型別進行比較。
不等於!=
與 !==
!=
與「! ==」兩者都是不等於,但是 !=
會替變數做自動轉型,而 !==
不會替變數自動轉型,推薦使用 !==
。
大於>與小於<的強制轉型
我有看到一個數字比大小的有趣例子,借來筆記一下:
天哪!怎麼會是這樣的結果! 3 < 2 < 1 的布林值竟然是 true ...天要塌了!
其實是因為 < 是由左向右( left to right )去做比較,下面來解釋一下:
所以才會得出 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)能將字串轉換為以十進位表示的浮點數。
來看一下範例:
.toString()、String()
String() 與 .toString() 都可以將值轉換為字串型別,差別在於 .toString() 在收到 null 、 undefined 和數字時會報錯。
Boolean()
Boolean() 可以用來將其他的資料型態轉型成布林值型態。還記得前面提過幾種會變成 false 的值嗎?
本來以為這個題目很好寫…..結果寫得一點都不輕鬆,也找不到方法寫得很有趣。幾乎每個知識點都有再深入研究的餘地,就像《浪人劍客》裡面老人對宮本武藏說的:「技是無限的,卻有鑽研的餘地!」
重點整理一下,如果可以掌握一些概念,之後還可以再仔細琢磨:
強制轉型分為兩種:
- 隱含的強制轉型:就是 JavaScript 在運算的過程中,依照它的規則在背地裡把值的型別轉換成其他類的型別。
- 四則運算中加法如果遇到「字串」的轉型最需要留意,其他的減乘除都會試圖轉換成數字來處理。
- 使用「===」相等的時候,會自動替兩側的變數轉型。當使用「===」全等的時候,不會替變數自動轉型,建議使用「===」來進行比較。
- 在布林值的轉型部分,請記得: undefined 、 Null 、 +0 、 -0 、 NaN 、空字串都會轉換成 false。
- 明顯的強制轉型:透過 JavaScript 提供的函式來進行變數型別轉換。
- 轉換為數值型別: Number() 、 parseInt() 、 parseFloat()
- 轉換為字串型別: toString() 、 String()
- 轉換為布林型別: Boolean()
我是初踏入前端領域的老學徒,如果有寫錯的地方還請大家包涵與指正,謝謝大家!
參考資料