關於JS類型隱式轉換的完整總結

無論是在技術聊天羣仍是論壇裏,總能碰到 x + y 等於多少的問題,好比 [] + {} == ?,若是你不瞭解其中的原理,那麼就插不上話,只能眼睜睜地等大佬解答了。javascript

Type

說到底仍是JS類型轉換的問題,首先咱們先溫習一下JS的7種內置類型:java

  • Number
  • String
  • Boolean
  • Null
  • Undefined
  • Object
  • Symbol

是否是感受還有Function,畢竟能用typeof獲取到?不,函數、數組都是Object的子類型。數組

類型分爲基本類型複合類型兩種,除了對象,其它都是基本類型。函數

To Primitive

發音:[ˈprɪmətɪv]
結構:toPrimitive(input, preferedType = number)
在對象的隱式轉換中,對象須要先轉成基本類型,並按照以下順序執行。學習

  1. 對象會先調用valueOf()
  2. 若是沒有valueOf這個方法或者valueOf返回的類型不是基本類型,那麼對象會繼續調用toString()方法。
  3. 若是沒有toString這個方法或者toString返回的類型不是基本類型,那麼直接拋出TypeError異常。
Uncaught TypeError: Cannot convert object to primitive value

接着,咱們看下各個對象的轉換實現code

對象 valueOf() toString()
Object 原值 字符串 => '[object Object]'
Function 原值 字符串 => 'function xyz() {...}'
Array 原值 字符串 => 'x,y,z'
Date 數字時間戳 字符串 => "Sat May 22 2021..."

Date的默認preferedType=string,即在加法運算中先執行toString()。在 - | * | / | +x | -x 等運算中,先執行valueOf()對象

數組的toString()能夠等效爲join(',')
其中,數組toString()時,遇到null, undefined都被忽略,遇到symbol直接報錯,遇到沒有toString()的對象也報錯。ip

[1, null, undefined, 2].toString() === '1,,,2';

// Uncaught TypeError: Cannot convert a Symbol value to a string
[1, Symbol('x')].toString()

// Uncaught TypeError: Cannot convert object to primitive value
[1, Object.create(null)].toString()

To Number

一些特殊值轉爲數字的例子,等下要用到字符串

Number("0") === 0;
Number("") === 0;
Number("   ") === 0;
Number("\n") === 0;
Number("\t") === 0;
Number(null) === 0;
Number(false) === 0;

Number(true) === 1;

Number(undefined); // NaN
Number("x"); // NaN

加減法 +-

加減法運算中遵循了一些隱式轉換規則:input

遇到對象先執行ToPrimitive轉換爲基本類型,而後按照基本類型的規則處理

({}).toString() === "[object Object]"
1 + {} === "1[object Object]"

[2, 3].toString() === "2,3"
1 + [2, 3] === "12,3"
[1] + [2, 3] === "1,2,3"

function test() {}
test.toString() === "function test() {}"
10 + test === "10function test() {}"

加法過程當中,遇到字符串,則會被處理爲字符串拼接

上面的對象最後也都轉成了字符串,遵循本條規則。接着來幾個純字符串的例子

1 + "1" === "11"
1 + 1 === 2
"1" + 1 === "11"
"1" + "1" === "11"

減法操做時,一概須要把類型轉換爲Number,進行數學運算

3 - 1 === 2
3 - '1' === 2
'3' - 1 === 2

// [].toString() => "" => Number(...) => 0
3 - [] === 3

// {}.toString() => "[object Object]" => Number(...) => NaN
3 - {} // NaN

加法操做時,遇到非字符串的基本類型,都會轉Number

1 + true === 2
1 + false === 1
1 + null === 1
1 + undefined // NaN

+ x 和 一元運算 +x 是等效的(以及- x),都會強制轉換成Number

+ 0 === 0
- 0 === -0
1 + + "1" === 2
1 + + + + ["1"] === 2
// 負負得正
1 + - + - [1] === 2
// 負負得正
1 - + - + 1 === 2
1 - + - + - 1 === 0

1 + + [""] === 1

// ["1", "2"].toString() => "1,2" => Number(...) => NaN
1 + + ["1", "2"] // NaN

// 吃根香蕉🍌
("ba" + + undefined + "a").toLowerCase() === "banana"

回到一開始拋出的問題[] + {},這樣太簡單了吧?

[].toString() === "";
{}.toString() === "[object Object]";

[] + {} === "[object Object]";

對象字面量{}在最前面則不表明對象

不是對象是什麼?是你的八塊腹肌?別急,看看經典的例子

{} + [] === 0;
{ a: 2 } + [] === 0;

這啥玩意?說好的"[object Object]"呢?

好吧,這是{}其實表明的是代碼塊,最後就變成了+ [],根據前面的原則,數組先被轉換成字符串"",接着由於+x的運算,字符串被轉成數字0

那 { a: 2 } 總該是對象了吧?其實這時候a不是表明對象屬性,而是被當成了標籤(label),標籤這東西IE6就已經有了。因此若是咱們寫成 { a: 2, b: 3 } + [] 這樣是會報錯的,逗號要改爲分號才能經過編譯。

symbol不能加減

若是在表達式中有symbol類型,那麼就會直接報錯。好比1 + Symbol("x")報錯以下:

Uncaught TypeError: Cannot convert a Symbol value to a number

寬鬆相等 ==

相等於全等都須要對類型進行判斷,當類型不一致時,寬鬆相等會觸發隱式轉換。下面介紹規則:

對象與對象類型一致,不作轉換

{} != {}
[] != {}
[] != []

對象與基本類型,對象先執行ToPrimitive轉換爲基本類型

// 當心代碼塊
"[object Object]" == {}
[] == ""
[1] == "1"
[1,2] == "1,2"

數字與字符串類型對比時,字符串老是轉換成數字

"2" == 2
[] == 0
[1] == 1
// [1,2].toString() => "1,2" => Number(...) => NaN
[1,2] != 1

布爾值先轉換成數字,再按數字規則操做

// [] => "" => Number(...) => 0
// false => 0
[] == false

// [1] => "1" => 1
// true => 1
[1] == true

// [1,2] => "1,2" => NaN
// true => 1
[1,2] != true

"0" == false
"" == false

null、undefined、symbol

null、undefined與任何非自身的值對比結果都是false,可是null == undefined 是一個特例。

null == null
undefined == undefined
null == undefined

null != 0
null != false

undefined != 0
undefined != false

Symbol('x') != Symbol('x')

對比 < >

對比不像相等,能夠嚴格相等(===)防止類型轉換,對比必定會存在隱式類型轉換。

對象老是先執行ToPrimitive爲基本類型

[] < [] // false
[] <= {} // true

{} < {} // false
{} <= {} // true

任何一邊出現非字符串的值,則一概轉換成數字作對比

// ["06"] => "06" => 6
["06"] < 2   // false 

["06"] < "2" // true
["06"] > 2   // true

5 > null     // true
-1 < null    // true
0 <= null    // true

0 <= false   // true
0 < false    // false

// undefined => Number(...) => NaN
5 > undefined // false

歡迎糾正錯誤,歡迎學習交流收藏。我是原罪,一個極客。

相關文章
相關標籤/搜索