JavaScript 類型轉換深度學習

wpzd6657 8年前發布 | 6K 次閱讀 深度學習 JavaScript開發 JavaScript

JavaScript 是一門弱類型語言,剛接觸的時候感覺方便快捷(不需要聲明變量類型了耶!),接觸久了會發現它帶來的麻煩有的時候不在預期之內

呵呵一笑,哪有這么夸張,可能有人看過這樣一段代碼

[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]][([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]((![]+[])[+!+[]]+(![]+[])[!+[]+!+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]+(!![]+[])[+[]]+(![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]()[+!+[]+[!+[]+!+[]]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]+(![]+[])[+!+[]]+([][[]]+[])[+!+[]]+(+![]+[![]]+([]+[])[([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[+!+[]]+([][[]]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]]+(!![]+[])[!+[]+!+[]+!+[]]+([]+[])[(![]+[])[+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+([][[]]+[])[+!+[]]+(!![]+[])[+[]]+([][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]]+[])[!+[]+!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[+!+[]+[+[]]]+(!![]+[])[+!+[]]]()[+!+[]+[!+[]+!+[]]]+(!![]+[][(![]+[])[+[]]+([![]]+[][[]])[+!+[]+[+[]]]+(![]+[])[!+[]+!+[]]+(!![]+[])[+[]]+(!![]+[])[!+[]+!+[]+!+[]]+(!![]+[])[+!+[]]])[!+[]+!+[]+[+[]]])()

這個占了好大的篇幅哈 3167 個字符,粘貼到瀏覽器的 Console 控制臺,直接彈出了 orange,隨叫隨到有不有

JSFuck 的變態程度達到了極致,因為它的理念是 Write any JavaScript with 6 Characters: []()!+

或許又有人說:這個只是搞怪的吧,實際誰這么寫代碼啊

說的沒錯,當一段代碼變得晦澀難懂的時候,甚至到上文的混亂字符(天書),卻能實現任意功能這就變得不可預期,也就是說 JS 代碼的安全性沒有保障

當然本文不會研究這些無意義的字符原理是怎么實現的因為人家的 Github 文檔已經描述的特別全面了,感興趣的可以研究下。

我們聊一聊每天能看到用到的方法底層是怎么解析的,熟知轉換分成兩種一種是隱式轉換,另一種是強制的類型轉換

隱式轉換

當遇到以下幾種情況,JavaScript會自動轉換數據類型:

  • 不同類型的數據進行互相運算

  • 對非布爾值類型的數據求布爾值

  • 對非數值類型的數據使用一元運算符(即 “+” 和 “-“)

隱式轉換為 Boolean

大多數在做 if 判斷時會用到,這里只需記住六個轉換為 false,其它全部為 true

  • null

  • undefined

  • NaN

  • ‘’

  • -0

  • +0

隱式轉換為 String

字符串的自動轉換,主要發生在加法運算時。當一個值為字符串,另一個值為非字符串,則后者轉為字符串。

'1' + 2  // '12'
'1' + true  // "1true"
'1' + false  // "1false"
'1' + {}  // "1[object Object]"
'1' + []  // "1"
'1' + function (){}  // "1function (){}"
'1' + undefined  // "1undefined"
'1' + null  // "1null"

隱式轉換為 Number

除了加法運算符有可能把運算子轉為字符串,其他運算符都會把兩側的運算子自動轉成數值

'5' - '2'  // 3
'5' * '2'  // 10
true - 1  // 0
false - 1  // -1
'1' - 1  // 0
'5' * []  // 0
false / '5'  // 0
'abc' - 1  // NaN
+'abc'  // NaN
-'abc'  // NaN
+true  // 1
-false  // 0

隱式轉換的基礎表現都在這了,強調的是這些轉換的背后都伴隨著強制轉換,使用 Boolean、Number 和 String,下面重點講一下強制轉換的原理

強制轉換

看到上面例子也許你已經有些許疑問了,比如上面的這個 '1' + {} 怎么就輸出 1[object Object] 了呢

如上面強調的,你會猜測首先執行 String({}) 得到 "[object Object]" ,然后再字符串拼接,是的我們總能得到轉換背后的實現原理,其實真實原理要比這個復雜,見下文

強制轉換為 Boolean

這里略過因為與隱式轉換相同,切記 []、{} 都轉換成 true

強制轉換為 String

基本類型的轉換結果與隱式轉換相同,這里說一下對象的轉換,加深上面引用例子的解析

對象轉換字符串分成三步

  1. 先調用toString方法,如果toString方法返回的是原始類型的值,則對該值使用String方法,不再進行以下步驟

  2. 如果toString方法返回的是復合類型的值,再調用valueOf方法,如果valueOf方法返回的是原始類型的值,則對該值使用String方法,不再進行以下步驟

  3. 如果valueOf方法返回的是復合類型的值,則報錯

再分解這個例子

String({})
// "[object Object]"

上面代碼相當于下面這樣

String({}.toString())
// "[object Object]"

如果 toString 方法和 valueOf 方法,返回的都不是原始類型的值,則 String 方法報錯

var obj = {
  valueOf: function () {
    console.log("valueOf");
    return {};
  },
  toString: function () {
    console.log("toString");
    return {};
  }
};

String(obj)
// TypeError: Cannot convert object to primitive value

我們不難看出可以對 toString 方法和 valueOf 方法進行改寫,測試其先后運行的順序也簡單的多

String({toString:function(){return 3;}})
// "3"

String({valueOf:function (){return 2;}})
// "[object Object]"

String({valueOf:function (){return 2;},toString:function(){return 3;}})
// "3"

結果表示toString方法先于valueOf方法執行

強制轉換為 Number

基本類型轉換如下

Number("123") // 123

Number("123abc") // NaN

Number("") // 0

Number(false) // 0

Number(undefined) // NaN

Number(null) // 0

對象轉換一樣要復雜些,與 String 唯一不同的就是 valueOf 方法在前, toString 方法在后,其它不贅述見上文例子。

isNaN() 并不陌生, isNaN({}) //true 的內在轉換過程是相同的

總結

其它的轉換原則還有很多,看到這我們還是不能解釋文章開始的代碼轉換的過程,掌握這些更多是保證正常書寫代碼規避錯誤的發生,十分好奇的可以研究下比較特殊的轉化原則,還有好多好多。

 

來自:http://orangexc.xyz/2016/10/31/JavaScript-type-conversion-depth-learning/

 

 本文由用戶 wpzd6657 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!