大頭照

你好,我是米米

菜雞前端工程師

米米

JS、何謂強制轉型、以及如何作到轉換型別?

前言

相信大家在剛學習JS的時候一定會遇到 轉型(coercion) 的問題,像是:

請問每一行a的值為何呢??

我想很多人一定會把它拿去console.log()裡面查詢吧~

JS會很貼心的(有夠雞婆)幫我們轉換型別,其中有分「顯性轉型(explicit coercion)」與「隱性轉型(implicit coercion)」,前者規規矩矩,你叫它轉型它才轉型;後者像一個死屁孩一樣會自動轉型,而且你還可能猜不透它會怎麼轉!!!

本次就來了解到底轉型是怎麼一回事ㄅ~

目錄:

顯性轉型與隱性轉型

剛剛前面有提過強制轉型分兩種:

  • 顯性轉型(explicit coercion):透過人工的方式,以函式的方法轉換值的型別。
  • 隱性轉型(implicit coercion):看到兩個不同型別的值就會自動判斷,把值轉換為相同型別,再做運算。

不管是顯性轉型或是隱性轉型,它們轉出來的型別就只會有布林值(boolean)字串(string)以及數字(number)這三種。

顯性轉型

透過明確的JS函式方法來轉換變數的型別,對應的函式方法分別有:

  • 轉換為布林型別:Boolean()
  • 轉換為字串型別:toString()String()
  • 轉換為數值型別:Number()parseInt()parseFloat()

這裡有個觀念要先澄清,變數若要轉換型別,原先的屬性下就有個類似轉換為其他型別的「方法」,因此呼叫這組方法便能轉換成其它型別。

大家可以執行上面的程式碼,你會發現a有好幾種函式,接著可以展開[[Prototype]],你會發現toString方法就在這裡。這就是為什麼每次在官方文件上找方法會看到像Number.prototype.toString()一樣長的原因。

可用函式

由於這牽涉到「物件原型」相互繼承的觀念,在這裡就不多做說明了,有興趣的朋友可以參考官方文件

轉型為布林型別:Boolean()

還記得前幾篇的[教學]UNDEFINED與NULL的比較曾提到過truth值與falsy值嗎?在這裡也需要用到喔~

truthy狀態 falsy狀態
布林值(Boolean) true false
字串(string) 除了空字串以外的字串 空字串
數字(number) 除了0之外的任意值 0
null、undefined 不可能 永遠
任何物件,包含{}[] 永遠 不可能

接下來到了看圖說故事的時間,顯示為truthy就為truefalthy就歸類為false,就是這麼簡單!

轉型為字串型別:toString()、String()

String().toString()都可以將值轉換為字串型別,差別在於後者在收到nullundefinednumber時會報錯。 String()的程式碼:

toString()的程式碼:

在我看來要如何記得toString收到nullundefinednumber時會報錯的方法就是「它這樣寫很奇怪」。

toString的寫法是把變數放在函式前面而非包在裡面,這就像我們不會把變數名稱開頭命名為數字,看起來就非常奇怪~(以上的想法僅供參考,如果不是請不要來打我QAQ

不過,假如用變數來代表numbertoString就可以用了,而nullundefined依然不能用。

轉型為數值型別:Number()、parseInt()、parseFloat()

  • Number():可以將「物件」轉化成數值。
  • parseInt():可以傳回由「字串」轉換而成的整數。
  • parseFloat():可以傳回由「字串」轉換而成的浮點數。

三者在遇到無法轉型的情況下,皆輸出NaN

Number()的程式碼:

parseInt()的程式碼:

仔細觀察上面的程式碼可以知道,Number()是將「物件」轉化成數值;parseInt()parseFloat()是將「字串」轉化成數值,因此後者會輸出堆NaN,因為它們都不是字串。(沒有列parseFloat是因為它跟parseInt差不多,等等它就會出現了。

不知道有沒有人眼尖發現在parseInt轉換陣列時,輸出的居然是數字?

因為剛剛講的都還只是基本用法,有差別的地方現在才開始:

  • Number():若「物件」夾雜不可轉換的值時,則全部輸出為NaN
  • parseInt():忽略前後空白,在遇到字元被無法解析時,會忽略那個字元與後面的所有字元,停止解析,並回傳目前為止的結果。另外,它真正的寫法為parseInt(string, radix)前者為要轉換的目標值;後者代表使用哪種進位制轉換,為選填。
  • parseFloat():只傳回第一個數字。前後空格會被省略。

到這裡顯性轉型就告一段落了,接著來看看隱性轉型。

隱性轉型

這是轉型中最GY的一個,因為它會自己幫你轉型,有時一個不注意,輸出的結果要嘛變成字串相加;要嘛變成NaN。還有很多奇奇怪怪例子,像是3<2<1會顯示true,這次就來讓我們好好了解其中的規則吧。

  • 轉換為布林型別:比較運算子、邏輯運算子、條件(三元)運算子
  • 轉換為字串型別:算數運算子
  • 轉換為數值型別:算數運算子

這裡列出大多數會看到的情形,因為它不像顯性轉型一樣有固定的公式可言,因此只能大致歸納出幾點原因。

轉換為布林型別:其實都是看truthy跟falsy值

老樣子,看到轉換為布林值就是要先上圖~

truthy狀態 falsy狀態
布林值(Boolean) true false
字串(string) 除了空字串以外的字串 空字串
數字(number) 除了0之外的任意值 0
null、undefined 不可能 永遠
任何物件,包含{}[] 永遠 不可能

比較運算子、邏輯運算子、條件(三元)運算子這三者跟轉換為布林型別有關,但最關鍵的還是「truthyfalsy值」身上,透過truthyfalsy值轉換成true或是false,再透過剛剛的三條運算子來判斷。

使用比較運算子:

這裡使用一般相等(==!=)來比較,因為一般相等會幫忙轉型別;而使用嚴格相等(===!==)就不用玩了,需要型別與值都相同才會相同。

符號 說明
一般相等(equality operator) == 將比較值轉換成同型別後比較,再比較兩者的值。(如字串8等同於數字8)
一般不相等 != 將比較值轉換成同型別後比較,再比較兩者的值,值不同視為不相等。(如字串8不等同於數字7)
嚴格相等(identity operator) === 先看型別再看值,兩者的值不會轉換型別。
嚴格不相等 !== 兩個不同型別的值,視為不相等。(如字串8不等同於數字8)

這裡有個比較有趣的題目,跟比大小有關:

大家覺得答案會是什麼呢?(提示:比較運算子是一次比較兩個)

準備公布答案了喔~

3…

2…

1…

答案皆為true。程式的多個比較需要使用到邏輯運算子(&&||),不能一整排刷過去R~

使用邏輯運算子:

邏輯運算子有AND、OR、NOT這三種,詳細使用方式請參考下表。

運算子 用法 描述
AND(&& 運算式1 && 運算式2 假如 運算式1 可以被轉換成 false的話,回傳 運算式1;否則,回傳 運算式2。 因此,&&只有在 兩個運算元都是True 時才會回傳 True,否則回傳 false
OR(|| 運算式1 || 運算式2 假如 運算式1 可以被轉換成 true的話,回傳 運算式1;否則,回傳 運算式2。 因此,||在 兩個運算元有任一個是True 時就會回傳 True,否則回傳 false
NOT(! !運算式 假如單一個運算元能被轉換成True時,回傳false , 不然回傳 true

使用條件(三元)運算子:

轉換為字串型別:使用加號

使用算數運算子時,+可以把數字相加,不過絕大多數我們都是將它作為字串相加,因為字串跟什麼相加都等於字串!!!

轉換為數值型別:可以使用加號,但是小心使用

前面提到算數運算子的+常常被拿來和字串相加,因此若想要轉換成數值則需要注意相加的對象是否為字串。

至於使用減乘除法(-*/)的情況,除了數值以外的其他基本型別都會透過Number()方法轉為數字。物件則在乘除的時候會透過Number()方法,轉為數字,在減法時透過valueOf()方法轉為數字。

我們來看看使用加號會如何:

看到number使用加號被污染那樣,其他的運算子在同樣的算式估計也沒辦法活得好好的,這裡就列出可能會翻車的例子:

看來確實都會出問題呢,值得關注的是當數值除以null0等概念為零的數值,輸出的竟然是無限大??

我在網路上找解答的時候也發現有趣的例子:

這個就牽扯到浮點數一開始的定義,但是我還是不太懂,在這裡附上相關連結,有興趣的朋友可以研究看看。

結語

前面講了這麼多,我們回過頭來複習一下:

  • 強制轉型轉換出來的型別有:布林型別、字串型別、數字型別。
  • 顯性轉型:有多種函式方法可以使用,轉換成布林型別注意truthyfalthy值;轉換成字串型別注意nullundefined;轉換成數值型別注意函式方法的使用規則。
  • 隱性轉型:自動轉譯成對應的型別,轉換成布林型別注意truthyfalthy值,轉換成字串型別通常都是用加號;轉換成數值型別使用算數運算子,但小心使用加號。

以上做個簡單的小整理。最後的貼心小建議就是盡量使用顯性轉型,比起隱性轉型的不確定性,使用顯性轉型至少還有個明確的函式方法讓你知道這裡有轉型~


參考資料

parseInt()、parseFloat() 與 Number()

ㄟ問你喔,強制轉型是什麼?轉換型別有規則可循嗎?(布林值、字串篇)

ㄟ問你喔,強制轉型是什麼?轉換型別有規則可循嗎?(數字型別篇)

何謂強制轉型、以及如何作到轉換型別?

感謝抖內

BUY ME A COFFEE
comments powered by Disqus
comments powered by Disqus

advertisement

recent post

categories

advertisement

about

你好,我是米米,是個剛畢業就已經成為社畜的前端工程師==