首頁  >  文章  >  web前端  >  JavaScript類型轉換深度學習

JavaScript類型轉換深度學習

高洛峰
高洛峰原創
2016-11-04 09:32:11992瀏覽

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

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

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

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

對於不知道原理出處的給大家一個地址:http://www.jsfuck.com/

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

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

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

當然本文不會研究這些無意義的字元原理是怎麼實現的因為人家的Github 文件已經描述的特別全面了,感興趣的可以研究下:https://github.com/aemkei/jsfuck

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

隱式轉換

當遇到以下幾種情況,JavaScript會自動轉換資料型別:

不同型別的資料互相運算

對非布林值型別的資料求布林值

對非數值類型的資料使用一元運算子(即"+" 和"-")

隱式轉換為Boolean

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

null

undefined

NaN

''

-0

+0

隱式轉換為運算

-0

+0

隱式轉換為運算

。當一個值為字串,另一個值為非字串,則後者轉為字串。

'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

隱式轉換的基礎表現都在這算子自動轉成數值

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

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

強制轉換

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

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

強制轉換為Boolean

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

強制轉換為String

基本型別的轉換結果與隱式轉換相同,這裡說一下物件的轉換,加深上面引用範例的解析

物件轉換字串分成三步驟

先呼叫toString方法,如果toString方法傳回的是原始型別的值,則對該值使用String方法,不再進行下列步驟

如果toString方法傳回的是複合型別的值,再呼叫valueOf方法,如果valueOf方法傳回的是原始型別的值,則對該值使用String方法,不再進行以下步驟

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

再分解這個例子

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

上面程式碼相當於下面這樣

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 方法報錯

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("123") // 123 
 
Number("123abc") // NaN 
 
Number("") // 0 
 
Number(false) // 0 
 
Number(undefined) // NaN 
 
Number(null) // 0

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

強制轉換為Number

基本型別轉換如下

rrreee

物件轉換一樣要複雜些,與String 唯一不同的就是valueOf 方法在前, toString 方法在後,其它不賘述見上文例子。

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

總結🎜🎜其它的轉換原則還有很多,看到這我們還是不能解釋文章開始的代碼轉換的過程,掌握這些更多是確保正常書寫程式碼規避錯誤的發生,十分好奇的可以研究下比較特殊的轉換原則,還有很多好多。 🎜🎜🎜🎜
陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn