無論是在技術聊天羣仍是論壇裏,總能碰到 x + y 等於多少的問題,好比 [] + {} == ?
,若是你不瞭解其中的原理,那麼就插不上話,只能眼睜睜地等大佬解答了。javascript
說到底仍是JS類型轉換的問題,首先咱們先溫習一下JS的7種內置類型:java
是否是感受還有Function,畢竟能用typeof獲取到?不,函數、數組都是Object的子類型。數組
類型分爲基本類型
和複合類型
兩種,除了對象,其它都是基本類型。函數
發音:[ˈprɪmətɪv]
結構:toPrimitive(input, preferedType = number)
在對象的隱式轉換中,對象須要先轉成基本類型,並按照以下順序執行。學習
valueOf()
。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()
一些特殊值轉爲數字的例子,等下要用到字符串
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
({}).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"
3 - 1 === 2 3 - '1' === 2 '3' - 1 === 2 // [].toString() => "" => Number(...) => 0 3 - [] === 3 // {}.toString() => "[object Object]" => Number(...) => NaN 3 - {} // NaN
1 + true === 2 1 + false === 1 1 + null === 1 1 + undefined // NaN
+ 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類型,那麼就會直接報錯。好比1 + Symbol("x")
報錯以下:
Uncaught TypeError: Cannot convert a Symbol value to a number
相等於全等都須要對類型進行判斷,當類型不一致時,寬鬆相等會觸發隱式轉換。下面介紹規則:
{} != {} [] != {} [] != []
// 當心代碼塊 "[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與任何非自身的值對比結果都是false,可是null == undefined
是一個特例。
null == null undefined == undefined null == undefined null != 0 null != false undefined != 0 undefined != false Symbol('x') != Symbol('x')
對比不像相等,能夠嚴格相等(===)防止類型轉換,對比必定會存在隱式類型轉換。
[] < [] // 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
歡迎糾正錯誤,歡迎學習交流收藏。我是原罪,一個極客。