Javascript中的類型轉換

Javascript爲何會有類型轉換

Javascirpt世界裏,不推薦大量的使用try...catch...,我想大概緣由:前端

  • JS裏任何類型之間的算數運算,邏輯運算和位運算都不會拋異常或者錯誤。例如 1/0 == Infinity, 0/0 = NaN, [ ] + 1 = '1' 等。因此catch到excepton/error的概率,相對於編譯型語言甚至於python/ruby等動態語言,是大大地下降了。python

  • try...catch...會在catch裏轉換到一個新的做用域,catch裏面調用本函數或者函數外的對象時,增長了一層做用域的查找,下降了運行效率web

  • 若是有未知的風險,確實能夠try...catch...。可是若是你的代碼裏有比較多的try...catch...,這就是bad smell,說明須要增強coding質量或者重構了。typescript

類型轉換法則

這裏討論JS裏對不一樣類型進行運算的時候,是如何作類型轉換的(通常是隱式轉換)。編程

加法運算

  1. 1 + '-1' = '1-1'
    基本類型之間相加時,只要其一是字符串,另一個也會先轉換爲字符串,結果就變成字符串的鏈接。後端

  2. [ ] + 1 = '1'
    引用類型和基本類型相加。引用類型先轉化爲基本類型。轉化過程:先查看對象的valueOf()方法是否返回基本類型。數組的valueOf返回它自己,屬於object類型,不是基本類型。因此再調用toString方法。空數組[]的toString返回空字符串。結果轉爲‘’ + 1. 返回字符串‘1’。數組

  3. [ ] + { } = [object Object]
    引用類型之間的加法。引用類型需先轉換爲基本類型。 參考2,空數組[]轉爲空字符串。相似地空對象{ } 轉換時,也先查看{ }.valueOf(). 由於 {}的valueof方法返回它自身,因此會調用{}.toString()返回‘[object Object]'。
    這樣結果變成 '' + '[object Object]' = '[object Object]'ruby

  4. 1 + null = 1
    由於已是基本類型,並且沒有字符串,因此會基於number類型運算。 null轉爲0, 結果是 1 + 0 = 1函數

  5. 1 + undefined = NaN
    undefined 轉爲NaN, so 1+ NaN = NaN學習

  6. false + null = 0
    都是基本類型並且沒有字符串,因此基於數字類型相加。 false轉爲0, null也爲0. 結果 0 + 0 = 0

  7. [1] + [2] = '12'
    分別調用toString方法以轉爲基本類型,獲得'1'和‘2’, '1' + '2' = '12'

加法之外的算數運算

加法之外的算數運算,若是有object類型(包括數組),先轉爲基本類型,這和加法運算是相同的。轉換過程也是先查看valueOf是否返回基本類型,若是不是,就調用toString(這裏假定toString都返回string。除非誰閒着沒事,非得給一對象的toString返回對象類型?)

和加法運算不一樣的是,轉換爲基本類型後,全部的基本類型再轉爲number類型,最終以number類型進行運算。

  1. 1 - "-1" = "-1"
    字符串「-1」轉爲number的-1, 結果1 - (-) = 2

  2. [ ] - 1 = -1
    [ ]先轉爲基本類型,是空字符。空字符再轉爲number爲0 ,結果是0 - 1 = -1

  3. [ ] / { }
    空數組轉爲基本類型是空字符,空對象轉爲基本類型是[object Object],兩者再分別轉爲數字類型是 0 和 NaN,最終結果爲0/NaN = NaN

  4. 1 / null
    都已經爲基本類型,因此只要把null轉爲number類型的0, 而後1 / 0 = Infinity

  5. 1 * undefined
    都已經爲基本類型,因此只要把undefined轉爲number類型的NaN, 而後1 * NaN = NaN

邏輯運算

  1. 1 && null = null.
    由於1 是真值,則返回第二個值, 即null

  2. null && undefined = null
    返回null,由於null是falsy,則返回第一個。

  3. 0 || {} = {}
    返回 {}. 由於0 是falsy,返回第二個

  4. 1 || null = 1
    返回1, 由於1是真值,返回第一個

位運算

  1. ~n = -(n+1)
    例如~25 = -26. 這裏是帶符號的取反。若是是無符號的取反,結果就不同了,有興趣的能夠在C語言裏試試 ~25u

  2. ~null = -1
    null轉爲0, ~0 = -(0+1) =-1

  3. ~undefined //SyntaxError: Invalid or unexpected token

  4. ~~23.5 = 23 ~~-23.5 = -23
    但 Math.floor(-23.5) = -24. 故而通常用~~取整數位

If 運算

if(-1)if (-1 == true) 是不同的。前者是真假判斷: -1是truthy,是真值。後者相似算術運算:先轉爲number,true 轉爲1, 故而 -1 == 1是假值。

小結

這裏總結了js類型轉換和運行的基本規律,但願是能夠知足基本的項目須要了。

後記

JS不一樣類型之間的類型轉換,確實是讓人撓頭的語言。我猜測多是JS產生的時候,web方興未艾,web工程師的編程功底尚未很規範(至少沒有今天這麼多資料書籍和培訓機構等),因此js容許類型轉換,不一樣類型之間運算時,保證不拋異常或者儘可能少拋。

可是如今前端和後端同樣的龐大了,顯然js的這樣那樣的技法每每會使工程師掉入陷阱。typescript應允而生,一個目的是也是幫助初級工程師寫出還能夠的代碼(另一個目的估計是下降後端開發者寫前端的門檻和思惟轉變)。從這角度解讀,ts也是爲知足項目工程和公司的須要。若是想深刻js學習,原生的js(es5/6)是繞不開的。

補證

前面提到「try...catch...會在catch裏轉換到一個新的做用域」,這是在《你不知道的JavaScript》中卷裏看到的。後來感受仍是作些論證,不然老以爲不踏實。看以下代碼:

function testException() {
    var error = 'outer error'
    try {
        throw 'inner error'
    } catch (error) {
        console.log(error)
        error = 'modify inner error'
    }
    
    // 這裏會輸出 outer error(而不是modify inner error),
    // 說明catch...裏修改的error,不是testExecution()函數做用域裏的,而是一個「新」做用域裏的error
    // 因此咱們可認爲,catch...建立了一個新的做用域。看來它和函數做用域的相似點,都接受「參數」
    console.log(error) 
}

testException()
相關文章
相關標籤/搜索