聊一聊 JS 中的『隱式類型轉換』

類型轉換還不行?還非得隱式?這是什麼高級玩意?編程

廢話很少說,咱們先上一盤?,額,不對,先看一個例子吧。編程語言

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 被隱式類型轉換了呢?

實際上在條件判斷運算 == 中的轉換規則是這樣的:

  1. 若是比較的二者中有布爾值(Boolean),會把 Boolean 先轉換爲對應的 Number,即 0 和 1,而後進行比較。

  2. 若是比較的雙方中有一方爲 Number,一方爲 String時,會把 String 經過 Number() 方法轉換爲數字,而後進行比較。

  3. 若是比較的雙方中有一方爲 Boolean,一方爲 String時,會將雙方轉換爲數字,而後再進行比較。

  4. 若是比較的雙方中有一方爲 Number,一方爲Object時,則會調用 valueOf 方法將Object轉換爲數字,而後進行比較。

例如:

1 == { valueOf: function() {return 1;} }    // true
1 + { valueOf: function() {return 1;} }    // 2

須要強調的是,在 Javascript 中,只有 空字符串數字0falsenullundefinedNaN 這 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"

隱式類型轉換會給咱們形成不少麻煩,那麼該怎麼避免呢?

建議在全部使用條件判斷的時候都使用全等運算符 === 來進行條件判斷。全等運算符會先進行數據類型判斷,而且不會發生隱式類型轉換。

相關文章
相關標籤/搜索