Javascript 隱式強制類型轉換

回龍觀自行車道

Javascript隱式強制類型轉換

Javascript中讓人詬病的技術點很多,類型轉換就是其一,甚至《Javascript語言精粹》的做者Douglas Crockford直接將Javascript中的類型轉換歸爲糟粕、雞肋(PS:聽說做者在平常開發中也常用到Javascript這一特性,看來萬事逃不過真香定律啊)。而類型轉換中最讓人詬病的就數+ 、 ==操做過度了。可是Javasript的類型轉化也不是一無用處。爲了讓你們在開發過程當中用的舒心、放心,因而就有了這篇博文。但願對你們有幫助。html

這裏直接上各類類型之間的轉換結果,若是沒有明白,那就帶着問題往下讀。web

+、==、||、&&

+ (重點)
1 + "1" // '11'
1 + "string" // "1tring" (加非數字字符串) 1 + true // 2 1 + false //1 1 + [] // "1" 1 + [1,2,3] // "11,2,3" 1 + {} // "1[object Object]" 1 + null // 1 1 + undefined // 1 null + undefined // NaN  true + 1 // 2 true + "1" // "true1" true + "true" // "truetrue" (加非數字字符串) true + true // 2 true + false // 1 true + [] // "true" true + [1,2,3] // "true1,2,3"  true + "true[object Object]" // NaN true + null // 1 true + undefined // NaN  false + 1 // 1 false + "1" // "false1" false + "string" // "falsestring" (加非數字字符串) false + false // 0 false + true // 1 false + [] // "false"  false + {} // "false[object Object]"  [] + 1 // "1" [] + "1" // "1"  [] + "string" // "string" (加非數字字符串) [] + true // "true" [] + false // "false" [] + [] // "" [1] + [1] // "11" [] + {} // "[object Object]" (注意!!!) [] + null // "null" [] + undefined // "undefined"  {} + 1 // 1  {} + "1" // 1  {} + "string" // NaN {} + true // 1  {} + false // 0 {} + [] // 0 (注意!!!) { a:1 } + [] // 0(注意!!!) {} + [1] // 1 (注意!!!) {} + [1,2,3] // NaN (注意!!!) {} + {} // "[object Object][object Object]" {} + null // 0 {} + undefined // NaN  -Infinity + Infinity // NaN 複製代碼

總結數組

  1. 若是某個操做數是字符串或者可以轉換爲字符串的話, + 將進行拼接操做。可見在 + 操做中字符串的拼接 優先級高於數字的 +。
  2. 若是一個操做數是對象(包括數組),則首先對其調用 ToPrimitive操做,該抽象操做再調用 [[DefalutValue]],以數字做爲上下文,保證了優先調用 valueOf()方法,可見在 + 操做時,引用類型內部調用 valueOf()方法的 優先級高於 toString()
  3. 數組或者對象在調用 valueOf()方法若是沒法獲取到基本類型值(數字),會轉而調用 toString()

代碼演示編輯器

// 這裏提供valueOf()方法,
var daRui = {  valueOf: function() {  return 18  },  toString: function() {  return "daRUI"  } }  daRui + 7 // 25 daRui + "7" // "187" daRui + "hello" // "18hello"  // 這裏僅提供toString()方法, var daRui = {  toString: function() {  return "daRUI"  } }  daRui + 7 // "daRUI7" daRui + " hello" // "daRUI hello"  複製代碼

特別說明flex

  1. 數組中的 toString()方法是通過改寫的,故 [1,2,3]會轉爲"1,2,3", [] 會轉爲""。
  2. 對象的 toString()方法會返回 "[object Class]", Object.prototype.toString.call([]) 返回 "[object Array]"。
  3. [] + {}獲得」[object Object]「,而 {} + [] 獲得 0。這是由於 {} (花括號)在JS中有兩種含義:
    1. {} 在 + 後面時,表示對象 {}
    2. {} 位於 + 前面時, {} 表示一個獨立的 空代碼塊,因此 {} + [] 操做至關於進行的是 +[](一元操做符轉換操做) 將 [] 轉爲0
==(重點)
1 == '1' // true
1 == true // true 1 == [] // false 1 == [1] // true 1 == {} // false  true == "1" // true true == "true" // false  true == [] // true true == [1] // true true == {} // false  [] == "1"// false [] == true // false [] == false // true [] == [] // false [] == {} // false [] == ![] // true (注意!!!)  {} == 1 // Unexpected token '==' {} == "1" // Unexpected token '==' {} == true // Unexpected token '==' {} == false // Unexpected token '==' {} == [] // Unexpected token '==' {} == {} // false  "0" == null // false "0" == undefined // false "0" == false // true (注意!!!) "0" == NaN // false "0" == 0 // true "0" == "" // false  false == null // false (注意!!!) false == undefined // false (注意!!!) false == NaN // false false == 0 // true (注意!!!) false == "" // true (注意!!!) false == [] // true (注意!!!) false == {} // false  "" == null // false "" == undefined //false "" == NaN // false "" == 0 //true (注意!!!) "" == [] // true (注意!!!) "" == {} // false  0 == null // false 0 == undefined // false 0 == NaN // false 0 == [] // true (注意!!!) 0 == {} // false +0 == -0 // true  null == null // true null == undefined // true null == "" // false null == 0 // false undefined == "" // false undefined == 0 // false  NaN == NaN // false 可使用isNaN() 判斷是否是NaN 複製代碼

總結ui

== 操做,最重要的時在兩個操做數的轉換過程!關於 == 操做ES5 規範11.9.3給出了明確規範:url

  1. 字符串和數字之間的相等比較:
    1. 若是Type(x)是數字,Type(y)是字符串,則返回 x == ToNumber(y)的結果。
    2. 若是Type(x)是字符串,Type(y)是數字,則返回 ToNumber(x) == y的結果。
  2. 其餘類型值和布爾類型之間的相等比較:
    1. 若是Type(x)是布爾類型,這返回 ToNumber(x) == y的結果
    2. 若是Type(y)是布爾類型,則返回 x == ToNumber(y) 的結果
  3. null和undefined之間的相等比較
    1. 若是x爲null,y爲undefined,則結果爲true
    2. 若是x爲undefined,y爲null,則結果爲true
  4. 對象和非對象之間的相等比較:
    1. 若是Type(x)是字符串或者數字,Type(y)是對象,則返回 x == ToPrimitive(y)的結果
    2. 若是Type(x)是對象,Type(y)是字符串或者數字,則返回 toPrimitive(x) == y的結果

== 相等操做中,若是兩邊的操做數不一樣的話,都會進行類型轉換,並且優先轉爲數字,再進行比較,若是轉換後還不一樣則再次轉換,直到相同爲止。這裏以 字符串類型 == 布爾類型作介紹:spa

  1. 首先字符串類型轉爲Number 類型,這時比較的是 數字類型 == 布爾類型
  2. 再將布爾類型轉爲Number類型,這時比較的是 數字類型 == 數字類型

這也就不難解釋爲何"0" == falseprototype

若是連個操做數中有引用類型,這會先將引用類型轉換爲基本類型,在進行上面的操做,進行比較。設計

再說[] == ![] // true:

  1. 這裏!操做的優先級是高於 == 的,![] 首先轉換爲false
  2. 此時比較雙方是 [] == false,這裏會將 [] 再次轉換爲 0
  3. 此時比較雙方是 0 == false,接下來就不難理解了
!!、&&、||(重點)
&&、||

&&與||邏輯運算符的特殊之處在於,二者返回的是兩個操做數中的一個(且僅一個),即選擇兩個操做數中的一個,而後返回它的。這兩個邏輯運算符首先會對第一個操做數執行條件判斷,若是其不是布爾值就先進行ToBoolean強制類型轉換,而後在執行條件判斷。

對於||來講,若是條件判斷結果爲true就返回第一個操做數的值,若是爲false就返回第二個操做數的值。

&&則相反,若是條件判斷結果爲true就返回第一個操做數的值,若是爲false就返回第一個操做數的值。 ——《你不知道的Javascript上卷》

18 || "daRui" // 18
undefined || "daRui" // "daRui" 18 && "daRui" // daRui null && "daRui" // null null || {} // {} null && {} // null 複製代碼

總結

  1. ||與&&返回的都是操做數中兩個中的一個,這個嚴格意義上說並非一種轉換,而是一種選擇

  2. 平常開發中的 if (a||b) {return true}的過程,實際上是先獲取到 a||b的值再進行的判斷

  3. 這裏說 ||和&&的緣由是它能夠簡化咱們平常開發中的代碼,使代碼更簡潔,例:

18 || "daRui" 
 // 至關於  18 ? 18 : "daRui"   18 && "daRui" // daRui  // 至關於  18 ? "daRui" : 18 複製代碼
!!

將值轉爲布爾值

// 除將下面的轉爲false其他所有爲true
!! "" !! 0 !! -0 !! +0 !! null !! undefined !! NaN 複製代碼

每一個人都有一個覺醒期,但覺醒的遲早決定我的的命運。 ——路遙

大哥,給個贊吧
大哥,給個贊吧

參考文獻:

  • 《你不知道的 Javascript》中卷
  • Javascript高級程序設計》
  • 《編寫可維護的 Javascript
  • ECMA5-262

本文使用 mdnice 排版

相關文章
相關標籤/搜索