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


我們都知道JavaScript的基本型別有以下幾種:

  1. String :字串,由一連串的字符 (characters) 組成。
  2. Number :數值,為 floating point number。
  3. Boolean :true 或 false。
  4. undefined :表示現在還沒有給值。
  5. null :不知道之前有沒有值,但是現在沒有值。
  6. Symbol :ES6 出現的新型別。

JavaScript 的型別不在於變數本身,而在於變數被賦予的值。

如果以上那些你都知道,那你該來看看JavaScript變態的部分—「強制轉型」( coercion )。

斯斯有兩種,「強制轉型」也有兩種:

  • 隱含的強制轉型 — implicit coercion
  • 明確的強制傳型(explicit coercion)

隱含的強制轉型 — implicit coercion

剛剛提到 JavaScript 的型別不在於變數本身,而在於變數被賦予的值

JavaScript 在運算的時候,如果看到兩個不同型別的值,就會自動判斷,把值轉換為相同型別,再做運算。很親切(變態)吧!!??

不多說,讓我們看一下例子,比較容易進入狀況:

let a = "1";      //字串
a = a + 2;        //'12', a為字串"1",數字2與字串相加,被轉型為字串"2"
a = a*2           //24 , 在乘法的時候,字串"12"與2相乘,字串被轉型為數值,得出的結果是數值 12
a = a + true      //25, 布林值遇到數值,被轉為數字1,相加後變成25
a = a * null      //0 , null遇到數值被轉為0,數值與0相乘變成0
a = a / undefined //NaN, undefined無法再被轉型為數字

以上這些「我變我變我變變變」的情形就是 JavaScript 變數的「強制轉型」,而且是 JavaScript 親切的、自動的、在背後運作的、「隱含的強制轉型」( implicit coercion )。一下變字串,一下有變成數字、一下變成布林值…比孫悟空72變還厲害。

這種「隱含的轉型」( implicit coercion )基本上可以轉成三種型別:

  • 自動轉換為布林值( ToBoolean )
  • 自動轉換為數值( ToNumber )
  • 自動轉換為字串( ToString )

四則運算時的強制轉型

JavaScript在做四則運算的時候跟小學課本教的一樣,由左而右「先乘除後加減」。

其中以加法(+)最需要注意!

如果是數值的運算,那沒有轉型的問題。「字串」的相加也沒有轉型的問題。

var x = 1 + 2;
console.log(x);  //3

var y = '歐陽鋒是' + '一隻癩哈蟆';
console.log(y);  //歐陽鋒是一隻癩哈蟆

只有在不同型別的狀況下才有轉型的問題:

  • 當加號 + 兩側有一個是字串的情形下,會將「非字串」的那一邊「自動轉型」為字串,再將兩個字串連接在一起。如果另一方為 number 、 boolean 、 object 的情況下, number 、 boolean 、 object 會去叫用它們的** .toString 「原型方法」**,把自己變成字串,再去和另一個字串組合。
  • 當一邊是數字,一邊是 undefined 的時候, undefined 會被試著轉為數字,變成 NaN ,任何數字與 NaN 相加都是 NaN 。
  • 當一邊是數字,加號另一邊是 null 的時候, null 會被轉為數字 0 。
//數字與字串相加
77 + '49'         //'7749'
77 + '四十九'      //'77四十九'
//字串與字串相加
'七七' + '四十九'  //'七七四十九'

77 + {}           //'77[object object]'

//當數字要跟undefined相加的時候,udefined會被嘗試轉為數字,也就是NaN,還記得NaN的型別是number嗎?
77 + unfined      //NaN
'七七' + unfined   //'七七undefined'

//當數字要與null相加時,null會被轉成數字 0 ;
77 + null          //77
'七七' + null       //77null

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

49 - '36'   //13

//字串會被轉為數字,也就是NaN
49 - 'abc' //NaN

//布林值的true,會被轉行為數字 1
49 - true  //48
//布林值的false,會被轉行為數字 0
49 - false  //49

49 - undefined  //NaN
//null會轉為數字0
49 - null       //49
49 - {}      //NaN
49 * '10'       //490
49 *  '四十九'   //NaN
49 * true       // 49
49 * false      //0
49 * {}         //NaN

下面附上變數在四則運算時的「自動轉型」規則:

四則運算 數字 基本型別非數字 物件
減法 正常運算 Number()方法轉為數字 透過valueOf()轉為數字
乘法 正常運算 Number()方法轉為數字 Number()方法轉為數字
除法 正常運算 Number()方法轉為數字 Number()方法轉為數字
加法 正常運算 如果是number、boolean透過toString()方法轉為字串,null或undefined透過String()轉為字串 toString()轉為字串

比較運算子的強制轉型

比較運算子用來比較兩側的數值,比較之後得到布林值 true 或 false。

一個等號 =,我們知道是「指定、賦值」的意思。

var x = 49;

在JavaScript中, == 是相等的意思,而 === 是全等的意思。

var x = 49;   //數字
var y = '49'; //字串

console.log(x == y);
//true,因為 == 在比較兩側的變數是否相等的時候,會自動幫變數轉型。

true == '1';   //true
false == '0';   //true

true === '1';   //false
false === '0';  //false

使用 == 相等的時候,會自動替兩側的變數轉型。

當使用 === 全等的時候,不會替變數自動轉型,是比較嚴謹的模式,也是比較推薦使用的方法。

比較特別的是,NaN不等於NaN,不管是 == 還是 ===,都是一樣 NaN 不等於 NaN 。

==的自動轉型規則:

  • 當遇到「字串」與「數字」做比較的時候,字串會透過 Number() 嘗試轉為數字,再進行比較。
  • 如果比較的一方為布林值,則 true 會轉為 1 , false 會轉為 0 。
  • == 的一側為物件型別,另一側為基本型別,物件型別會透過 valueOf() ,轉為對應的基本型別進行比較。

不等於!=!==

!= 與「! ==」兩者都是不等於,但是 != 會替變數做自動轉型,而 !== 不會替變數自動轉型,推薦使用 !==

大於>與小於<的強制轉型

我有看到一個數字比大小的有趣例子,借來筆記一下:

console.log(1 < 2 < 3); // true
console.log(3 < 2 < 1); // true

天哪!怎麼會是這樣的結果! 3 < 2 < 1 的布林值竟然是 true ...天要塌了!

其實是因為 < 是由左向右( left to right )去做比較,下面來解釋一下:

console.log(1 < 2 < 3);
1<2 //true
true < 3 //true轉為數字1,1<3,結果為true。

console.log(3 < 2 < 1); 
3 < 2 //false
false < 1 // false轉為數字0,0<1,所以結果為true

所以才會得出 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)能將字串轉換為以十進位表示的浮點數。

來看一下範例:

Number('123');        //123
Number('華山論劍');   //NaN
Number('9陰真經');    //NaN
Number(null);         //0
Number(true)          //1
Number([]);           //0
Number([1]);          //1
Number([1,2,3]);      //NaN
Number({});           //NaN

parseInt('9陰真經');  //9
parseInt('九陰真經'); //NaN
parseInt(101010,2);   //42
parseFloat('3.1416')  //3.1416

.toString()、String()

String() 與 .toString() 都可以將值轉換為字串型別,差別在於 .toString() 在收到 null 、 undefined 和數字時會報錯。

String(123)          //'123'
String(null)         //'null'
String('undefined')  //'undefined'
String(true)         //'true'

true.toString()      //'true'
123.toString()
//Uncaught SyntaxError: Invalid or unexpected token
null.toString()
//Uncaught TypeError: Cannot read properties of null (reading 'toString')
    
undefined.toString()
//Uncaught TypeError: Cannot read properties of undefined (reading 'toString')
    

Boolean()

Boolean() 可以用來將其他的資料型態轉型成布林值型態。還記得前面提過幾種會變成 false 的值嗎?

Boolean(100)       //true
Boolean('100')     //true
Boolean('')        //false
Boolean(false)     //false
Boolean(undefined) //false
Boolean(null)      //false
Boolean('""')      //true
Boolean('false')   //true

本來以為這個題目很好寫…..結果寫得一點都不輕鬆,也找不到方法寫得很有趣。幾乎每個知識點都有再深入研究的餘地,就像《浪人劍客》裡面老人對宮本武藏說的:「技是無限的,卻有鑽研的餘地!」

重點整理一下,如果可以掌握一些概念,之後還可以再仔細琢磨:

強制轉型分為兩種:

  • 隱含的強制轉型:就是 JavaScript 在運算的過程中,依照它的規則在背地裡把值的型別轉換成其他類的型別。
    • 四則運算中加法如果遇到「字串」的轉型最需要留意,其他的減乘除都會試圖轉換成數字來處理。
    • 使用「===」相等的時候,會自動替兩側的變數轉型。當使用「===」全等的時候,不會替變數自動轉型,建議使用「===」來進行比較。
    • 在布林值的轉型部分,請記得: undefined 、 Null 、 +0 、 -0 、 NaN 、空字串都會轉換成 false。
  • 明顯的強制轉型:透過 JavaScript 提供的函式來進行變數型別轉換。
    • 轉換為數值型別: Number() 、 parseInt() 、 parseFloat()
    • 轉換為字串型別: toString() 、 String()
    • 轉換為布林型別: Boolean()

我是初踏入前端領域的老學徒,如果有寫錯的地方還請大家包涵與指正,謝謝大家!

參考資料


何謂強制轉型、以及如何作到轉換型別?
https://popeye-ux.github.io/2021/10/28/typeConversions/
作者
POPEYE
發布於
2021年10月28日
許可協議