從兩個小例子看js中的隱式型別轉換

R-B發表於2021-09-09

廢話不多說,我們先來看第一個例子吧。
某天,我遇到了這樣一個問題:給出變數a和b的定義,使下面三個語句的輸出結果都為true。

console.log(ab);

看到題目的我第一反應是懵逼的,還有這樣的操作???然後一開始的思路是往各種神奇的值上面找,比如undefined,null,NaN,“”這樣的值,自然是沒有得到想要的結果了。
但事實上,真的存在。來看程式碼:

function A(){    this.a = 1;
}

A.prototype = {    toString: function(){        return this.a += 2;
    }
}var a = new A();var b = 5;console.log(a  b);

上面的程式碼不難理解:變數a是透過建構函式A建立的物件,變數b就是一個很簡單的數值。一開始,因為a是透過建構函式A建立的物件,所以值為1.然後每一次在執行            console.log()的時候,會呼叫一次A的toString方法。所以,在第一個console.log()的時候,a的值變成了3,而b的值是5,所以atrue;第二個console.log()的時候,a的值變成了5,而b的值還是5,所以a=btrue;第三個console.log()的時候,a的值變成了7,而b的值依舊是5,所以a>btrue
經過上面的分析,我們似乎開啟了一個新世界的大門,這裡涉及到一個比較重要的概念:隱式型別轉換。在上面的例子裡,a和b是兩個完全不一樣的型別,但是它們進行了比較,還得出了結果,這就說明有一個型別在比較的過程中轉換成了另一個型別。
這裡需要提到一些規範來幫助我們更好的理解。
(小於大於的比較規則和相等是一樣的。)
對於字串和數字來說,ES5規範11.9.3.4.5這樣規定:

(1)如果Type(x)是數字,Type(y)是字串,則返回x == ToNumber(y)的結果
(2)如果Type(x)是字串,Type(y)是數字,則返回ToNumber(x) == y的結果

對於其他型別和布林型別的比較,規範11.9.3.6.7這樣規定:

(1)如果Type(x)是布林型別,則返回ToNumber(x) == y的結果
(2)如果Type(y)是布林型別,則返回x == ToNumber(y)的結果

對於null和undefined來說,ES5規範11.9.3.2.3這樣規定:

(1)如果x為null,y為undefined,則結果為x == y
(2)如果x為undefined,y為null,則結果為x == y

也就是說,null和undefined是相等的。
對於物件和非物件來說,ES5規範11.9.3.8.9這樣規定:

(1)如果Type(x)是字串或數字,Type(y)是物件,則返回x == ToPrimitive(y)的結果
(2)如果Type(x)是物件,Type(y)是字串或數字,則返回ToPrimitive(x) == y的結果

基本就是上面這幾種常見的型別的比較了。然後出現了一個我們好像不太常見的東西:ToPrimitive()這個方法。我們來簡單瞭解一下:
物件(或者陣列)再進行比較或者型別轉換的時候,先會被轉換為相應的基本型別值,然後再根據需要進行轉換。再轉換為基本型別值的時候,抽象操作ToPrimitive會先檢查該值是否擁有valueOf()方法。如果有且返回基本型別值,就使用該值作為基本型別值,如果沒有就使用toString()方法的返回值作為基本型別值。
上面例子中的相等操作我們使用了==,而不是===。對於這二者的區別,我們經常聽到的是,==是不嚴格相等,只要值相等即可,而===是嚴格相等,必須值和型別都相等才可以。對於==來說,型別不重要,也就是說在這個過程中是包含了型別轉換的。所以,在YouDontKnowJS這本書中,給出的正確解釋是:

==允許在相等比較總進行強制型別轉換,而===不允許。

然後我們再來看第二個例子吧
題目是這樣的:[1]+[2]-[3]=?
這次打算先分析再給出答案,順便大家也可以自己想想結果是什麼。
首先我們看到加減運算子左右兩邊的值都是陣列,那前面提到過對於陣列的處理。因為陣列的valueOf()操作無法得到簡單的基本型別值,所以會呼叫toString(),這樣的話上面那個式子就變成了"1"+"2"-"3"=?。現在這個式子相信大家都比較熟悉了,不過不知道會不會有人一時頭腦發熱,把答案想成了0。
然後我們繼續往下,因為是加減運算子,所以我們從左至右開始計算,"1"+"2"這個結果到底是3還是12呢。那就記住簡單的一句話:如果有一個值是字串,那麼就進行字串拼接,否則進行數字加法。那麼很明顯,這裡是2個字串,進行字串拼接,得到"12"
好了,到目前為止,式子已經變成了"12"-"3"了,這應該已經很明顯了吧,字串拼接是肯定不可能的,那就是進行數字運算了,那就是最簡單的12-3了,所以最終結果就是9。
其實這個例子裡的透過加減運算子進行隱式型別轉換在我們日常程式碼中經常出現,只是可能大家沒有特別關注,比如a + ""是把a轉換為字串;a - 0是把a轉換為數字。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/4560/viewspace-2800797/,如需轉載,請註明出處,否則將追究法律責任。

相關文章