舉個例子:前端
console.log(1 + '1')
在 JavaScript 中,這是徹底能夠運行的,不過你有沒有好奇,爲何 1 和 '1' 分屬不一樣的數據類型,爲何就能夠進行運算呢?git
這實際上是由於 JavaScript 自動的將數據類型進行了轉換,咱們一般稱爲隱式類型轉換。可是咱們都知道,+
運算符既能夠用於數字加法,也能用於字符串拼接,那在這個例子中,是將數字 1
轉成字符串 '1'
,進行拼接運算?仍是將字符串 '1'
轉成數字 1
,進行加法運算呢?github
先賣個關子,雖然估計你也知道答案。今天,咱們就常見的隱式類型轉化的場景進行介紹。面試
console.log(+'1');
當 + 運算符做爲一元操做符的時候,查看 ES5規範1.4.6,會調用 ToNumber
處理該值,至關於 Number('1')
,最終結果返回數字 1
。數組
那麼下面的這些結果呢?微信
console.log(+[]); console.log(+['1']); console.log(+['1', '2', '3']); console.log(+{});
既然是調用 ToNumber
方法,回想《JavaScript 深刻之頭疼的類型轉換(上)》中的內容,當輸入的值是對象的時候,先調用 ToPrimitive(input, Number)
方法,執行的步驟是:閉包
obj
爲基本類型,直接返回valueOf
方法,若是返回一個原始值,則 JavaScript
將其返回。toString
方法,若是返回一個原始值,則JavaScript
將其返回。JavaScript
拋出一個類型錯誤異常。以 +[]
爲例,[]
調用 valueOf
方法,返回一個空數組,由於不是原始值,調用 toString
方法,返回 ""
。app
獲得返回值後,而後再調用 ToNumber
方法,""
對應的返回值是 0
,因此最終返回 0
。函數
剩下的例子以此類推。結果是:工具
console.log(+['1']); // 1 console.log(+['1', '2', '3']); // NaN console.log(+{}); // NaN
如今 +
運算符又變成了二元操做符,畢竟它也是加減乘除中的加號
1 + '1'
咱們知道答案是 '11',那 null + 1
、[] + []
、[] + {}
、{} + {}
呢?
若是要了解這些運算的結果,不可避免的咱們要從規範下手。
規範地址:http://es5.github.io/#x11.6.1
不過此次就不直接大段大段的引用規範了,直接給你們講簡化後的內容。
到底當執行 +
運算的時候,會執行怎樣的步驟呢?讓咱們根據規範11.6.1
來捋一捋:
當計算 value1 + value2時:
規範的內容就這樣結束了。沒有什麼新的內容,ToString
、ToNumber
、ToPrimitive
都是在《JavaScript 深刻之頭疼的類型轉換(上)》中講到過的內容,因此咱們直接進分析階段:
讓咱們來舉幾個例子:
console.log(null + 1);
按照規範的步驟進行分析:
接下來:
ToNumber(null)
的結果爲0,(回想上篇 Number(null)),ToNumber(1)
的結果爲 1
因此,null + 1
至關於 0 + 1
,最終的結果爲數字 1
。
這個還算簡單,看些稍微複雜的:
console.log([] + []);
依然按照規範:
因此,[] + []
至關於 "" + ""
,最終的結果是空字符串""
。
看個更復雜的:
// 二者結果一致 console.log([] + {}); console.log({} + []);
按照規範:
因此,[] + {}
至關於 "" + "[object Object]"
,最終的結果是 "[object Object]"。
下面的例子,能夠按照示例類推出結果:
console.log(1 + true); console.log({} + {}); console.log(new Date(2017, 04, 21) + 1) // 這個知道是數字仍是字符串類型就行
結果是:
console.log(1 + true); // 2 console.log({} + {}); // "[object Object][object Object]" console.log(new Date(2017, 04, 21) + 1) // "Sun May 21 2017 00:00:00 GMT+0800 (CST)1"
以上的運算都是在 console.log
中進行,若是你直接在 Chrome
或者 Firebug
開發工具中的命令行直接輸入,你也許會驚訝的看到一些結果的不一樣,好比:
咱們剛纔才說過 {} + []
的結果是 "[object Object]"
吶,這怎麼變成了 0
了?
不急,咱們嘗試着加一個括號:
結果又變成了正確的值,這是爲何呢?
其實,在不加括號的時候,{}
被當成了一個獨立的空代碼塊,因此 {} + []
變成了 +[]
,結果就變成了 0
一樣的問題還出如今 {} + {}
上,並且火狐和谷歌的結果還不同:
> {} + {} // 火狐: NaN // 谷歌: "[object Object][object Object]"
若是 {}
被當成一個獨立的代碼塊,那麼這句話至關於 +{}
,至關於 Number({})
,結果天然是 NaN
,但是 Chrome
卻在這裏返回了正確的值。
那爲何這裏就返回了正確的值呢?我也不知道,歡迎解答~
"=="
用於比較兩個值是否相等,當要比較的兩個值類型不同的時候,就會發生類型的轉換。
關於使用"=="進行比較的時候,具體步驟能夠查看規範11.9.5:
當執行x == y 時:
若是x與y是同一類型:
x是數字:
以爲看規範判斷太複雜?咱們來分幾種狀況來看:
console.log(null == undefined);
看規範第二、3步:
- x是null而且y是undefined,返回true
- x是undefined而且y是null,返回true
因此例子的結果天然爲 true
。
這時候,咱們能夠回想在《JavaScript專題之類型判斷(上)》中見過的一段 demo
,就是編寫判斷對象的類型 type
函數時,若是輸入值是 undefined
,就返回字符串 undefined
,若是是 null
,就返回字符串 null
。
若是是你,你會怎麼寫呢?
下面是 jQuery 的寫法:
function type(obj) { if (obj == null) { return obj + ''; } ... }
console.log('1' == 1);
結果確定是true,問題在因而字符串轉化成了數字和數字比較仍是數字轉換成了字符串和字符串比較呢?
看規範第四、5步:
4.x是數字,y是字符串,判斷x == ToNumber(y)5.x是字符串,y是數字,判斷ToNumber(x) == y
結果很明顯,都是轉換成數字後再進行比較
console.log(true == '2')
當要判斷的一方出現 false
的時候,每每最容易出錯,好比上面這個例子,憑直覺應該是 true
,畢竟 Boolean('2')
的結果但是true,但這道題的結果倒是false。
歸根到底,仍是要看規範,規範第六、7步:
6.x是布爾值,判斷ToNumber(x) == y7.y是布爾值,判斷x ==ToNumber(y)
當一方出現布爾值的時候,就會對這一方的值進行ToNumber處理,也就是說true會被轉化成1,
true == '2'
就至關於 1 == '2'
就至關於 1 == 2
,結果天然是 false
。
因此當一方是布爾值的時候,會對布爾值進行轉換,由於這種特性,因此儘可能少使用 xx == true
和 xx == false
的寫法。
好比:
// 不建議 if (a == true) {} // 建議 if (a) {} // 更好 if (!!a) {}
console.log( 42 == ['42'])
看規範第八、9步:
- x不是字符串或者數字,y是對象,判斷x == ToPrimitive(y)
- x是對象,y不是字符串或者數字,判斷ToPrimitive(x) == y
以這個例子爲例,會使用 ToPrimitive
處理 ['42']
,調用valueOf
,返回對象自己,再調用 toString
,返回 '42'
,因此
42 == ['42']
至關於 42 == '42'
至關於42 == 42
,結果爲 true
。
到此爲止,咱們已經看完了第二、三、四、五、六、七、八、9步,其餘的一律返回 false。
再多舉幾個例子進行分析:
console.log(false == undefined)
false == undefined
至關於 0 == undefined
不符合上面的情形,執行最後一步 返回 false
console.log(false == [])
false == []
至關於 0 == []
至關於 0 == ''
至關於 0 == 0
,結果返回 true
console.log([] == ![])
首先會執行 ![]
操做,轉換成 false,至關於 [] == false
至關於 [] == 0
至關於 '' == 0
至關於 0 == 0
,結果返回 true
最後再舉一些會讓人踩坑的例子:
console.log(false == "0") console.log(false == 0) console.log(false == "") console.log("" == 0) console.log("" == []) console.log([] == 0) console.log("" == [null]) console.log(0 == "\n") console.log([] == 0)
以上均返回 true
除了這兩種情形以外,其實還有不少情形會發生隱式類型轉換,好比if
、? :
、&&
等狀況,但相對來講,比較簡單,就再也不講解。
JavaScript 深刻系列目錄地址:https://github.com/mqyqingfen...
JavaScript 深刻系列預計寫十五篇左右,旨在幫你們捋順JavaScript底層知識,重點講解如原型、做用域、執行上下文、變量對象、this、閉包、按值傳遞、call、apply、bind、new、繼承等難點概念。
若是有錯誤或者不嚴謹的地方,請務必給予指正,十分感謝。若是喜歡或者有所啓發,歡迎 star,對做者也是一種鼓勵。
如今是校招季,淘系前端正在幫助21屆同窗們收割大廠offer,專門建立了交流羣,能夠在這裏提問題,交流面試經驗,這裏也提供了簡歷輔導和答疑解惑等服務,加淘小招微信邀你入羣,微信號 taoxiaozhao233