0%

JS魔術師 implicit coercion

前言

和小夥伴討論到 implicit coercion 來研究研究

一開始討論到 為啥String前面 加上 一個 +
JS 就會幫你轉成Number
神奇神奇

amazing

來個例子

1
2
3
4
5
6

let obj = {
strNum:"456"
}

console.log(+obj.strNum + 789)

輸出是 1245

  • 前面+會讓把type轉成number

酷!!!

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

找了資料才發現叫做 :「強制轉型」(coercion)

「強制轉型」有兩種

  • 隱含的強制轉型 — implicit coercion

  • 明確的強制傳型 — explicit coercion

隱含的強制轉型 — implicit coercion

JavaScript 在運算的時候,如果看到兩個不同型別的值,就會自動判斷,把值轉換為相同型別,再做運算。

舉個例子:

1
2
3
4
5
6
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 )。
一下變字串,一下有變成數字、一下變成布林值

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

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

四則運算時的強制轉型

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

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

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

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

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

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

  • 當加號 + 兩側有一個是字串的情形下,會將「 非字串 」的那一邊「自動轉型」為字串,再將兩個字串連接在一起。

    • 如果另一方為 numberbooleanobject 的情況下,
      numberbooleanobject 會去叫用它們的 *** .toString 「原型方法」**,把自己變成 **字串**,再去和另一個 字串 組合。
  • 當一邊是數字,一邊是 undefined 的時候,
    undefined 會被試著轉為數字,變成 NaN ,任何數字NaN 相加都是 NaN

  • 當一邊是數字,加號另一邊是 null 的時候,
    null 會被轉為數字 0

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//數字與字串相加
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() 方法轉為數字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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。

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

1
var x = 49;  //X 的值 =49

==相等的意思,而 ===全等的意思。

1
2
3
4
5
6
7
8
9
10
11
12
var x = 49;   //數字
var y = '49'; //字串

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

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

true === '1'; //false
false === '0'; //false
1==='1' //false 因為===比較嚴格 會連型態也一起比較

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

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

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

==的自動轉型規則

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

不等於!= 與 !==

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


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

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

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

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

驚訝

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

1
2
3
4
5
6
7
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 的結果。

I see

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
2
3
4
5
6
7
8
9
10
11
12
13
14
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() 在收到 nullundefined數字時會報錯。

1
2
3
4
5
6
7
8
9
10
11
12
13
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 的值嗎?

1
2
3
4
5
6
7
8
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()

References

你的支持是我活力的來源 :)