類型轉換還不行?還非得隱式?這是什麼高級玩意?編程
廢話很少說,咱們先上一盤?,額,不對,先看一個例子吧。編程語言
3 + true
實際上在大多數編程語言中,都會認爲上面這個表達式是錯誤的。由於布爾表達式與算術運算是不兼容的。尤爲是在靜態語言中,甚至不會被運行運行。即便是動態語言中,一般雖然可讓程序運行,可是會拋出一個異常。函數
然而,然而, Javascript 不只運行程序可以正常運行,並且還會順利地產生結果 4。Javascript 真的是對類型錯誤出奇的寬容啊。看起來很像是一件好事對不對?測試
基本上,在 Javascript 中,只有在一些極少數狀況下才會由於類型錯誤而拋出一個異常。諸如: 調用非函數對象或者獲取 null / undefined 的屬性時。code
可是在大多數狀況下,Javascript 都是不會拋出異常的。這個『小婊砸』反而按照多種多樣的轉換協議偷偷的強制轉換爲她指望的值。諾,你看,還花樣轉換呢,真會玩嘛。這就是所謂的『隱式類型轉換』。對象
那麼,上面那個例子中,到底是發生了什麼樣的轉換方式呢?ip
首先,Javascript 這個『小婊砸』在遇到算數運算符(-
、*
、/
和 %
)的時候會在運算以前將參與運算的雙方轉換成數字。字符串
那麼問題又來了,true
怎麼就轉換成數字了呢?實際上咱們經過 Number(true)
就能夠看到, true
轉換爲數字以後就是爲 1,相反,false
轉換爲數字以後就對應爲 0。io
細心的你可能發現我在上面並無提到 +
運算符,那是由於它更復雜。由於它既承擔着數字相加,又肩負着字符串鏈接操做的重任。具體的行爲取決於參數的類型。console
可是,若是一個數字和一個字符串相加,會碰撞出什麼樣的火花呢?
顯然 Javascript 這個『小婊砸』更偏心字符串多一點,她會將數字(toString()
)轉換爲字符串,而後執行字符串鏈接操做。
例如:
"1" + 2; // "12" 1 + "2"; // "12"
可是,注意,Javascript 對操做順序很是敏感,以致於會發生這樣的事情:
1 + 2 + "3"; // "33"
由於加法運算是自左向右的,所以它等同於下面的表達式:
(1 + 2) + "3"; // "33"
再來看這一個例子:
if (1 == true) { alert("true"); } else { alert("false"); }
相信你必定輕鬆的猜到告終果對不對?
可是,哼,你覺得個人問題會這麼簡單麼?那豈不是過小看你了。
咱們都知道,Javascript 中,數字 0
爲假,非0
均爲真, 那麼我想問的是,在上面的條件語句中,究竟是 1
被隱式類型轉換了呢仍是 true
被隱式類型轉換了呢?
實際上在條件判斷運算 ==
中的轉換規則是這樣的:
若是比較的二者中有布爾值(Boolean),會把 Boolean
先轉換爲對應的 Number,即 0 和 1,而後進行比較。
若是比較的雙方中有一方爲 Number
,一方爲 String
時,會把 String
經過 Number()
方法轉換爲數字,而後進行比較。
若是比較的雙方中有一方爲 Boolean
,一方爲 String
時,會將雙方轉換爲數字,而後再進行比較。
若是比較的雙方中有一方爲 Number
,一方爲Object
時,則會調用 valueOf
方法將Object
轉換爲數字,而後進行比較。
例如:
1 == { valueOf: function() {return 1;} } // true 1 + { valueOf: function() {return 1;} } // 2
須要強調的是,在 Javascript 中,只有 空字符串
、數字0
、false
、null
、undefined
和 NaN
這 6 個值爲假以外,其餘全部的值均爲真值。
說到 NaN
,就不得不提一下 isNaN()
方法,isNaN()
方法自帶隱式類型轉換,該方法在測試其參數以前,會先調用 Number()
方法將其轉換爲數字。因此 isNaN('1')
這個語句中明明用一個字符串去測試,返回值仍然爲 false
也就不足爲怪了。
在 +
號運算中還有一種更復雜的狀況,那就是數字/字符串和對象進行運算的時候,上面已經舉例說明了數字和對象運算的狀況,咱們再來講一下字符串和對象運算的狀況。
當字符串和對象進行 +
運算的時候,Javascript 會經過對象的 toString()
方法將其自身轉換爲字符串,而後進行鏈接操做。
"1" + { toString: function() {return 1;} } // "11"
之因此說它特殊,是由於當一個對象同時包含 toString()
和 valueOf()
方法的時候,運算符 +
應該調用哪一個方法並不明顯(作字符串鏈接仍是加法應該根據其參數類型,可是因爲隱式類型轉換的存在,類型並不顯而易見。),Javascript 會盲目的選擇 valueOf()
方法而不是 toString()
來解決這個問題。這就意味着若是你打算對一個對象作字符串鏈接的操做,但結果倒是......
var obj = { toString: function() { return "Object CustomObj"; }, valueOf: function() { return 1; } }; console.log("Object: " + obj); // "Object: 1"
隱式類型轉換會給咱們形成不少麻煩,那麼該怎麼避免呢?
建議在全部使用條件判斷的時候都使用全等運算符 ===
來進行條件判斷。全等運算符會先進行數據類型判斷,而且不會發生隱式類型轉換。