正文從這開始~編程
JavaScript是一門神奇且奇妙的編程語言,咱們有時候用它來寫一些看似瘋狂的代碼,但這些代碼依然可被執行且運行結果十分有趣。JavaScript 試圖幫助咱們將一些數據類型轉化爲咱們所認爲的數據類型。數組
若是咱們定義一個字符串常量,它會假設咱們但願添加的是文本形式,因此 JavaScript 會把它轉化爲字符串類型。瀏覽器
若是咱們加上『+』或『-』前綴,JavaScript 會認爲咱們須要它以數值形式表示,若是條件容許,它甚至會把字符串也轉換爲數值類型。編程語言
若是咱們添加「表示否認的符號」,JavaScript 會將它轉換爲布爾類型。函數
咱們能夠利用 " [ " ," ] " ," ( " ," ) " ," ! " 和 " + " 六個字符作一些神奇的事情,若是你如今使用電腦瀏覽器閱讀這篇文章,你能夠在閱讀的同時,打開瀏覽器的控制檯,複製代碼,粘貼並執行。工具
讓咱們從基礎開始,先記住如下黃金法則:測試
「 ! 」後面接的字符會被轉換爲布爾值。code
「 + 」後面接的字符會被轉換爲數值。對象
「 [ ] 」後面接的字符會被轉換爲字符串。ip
來看下面的例子:
你須要知道,字符串能夠像數組同樣,以方括號下標的形式從字符串檢索特定字母:
你也應該知道,咱們也能夠將多個字符鏈接成字符串,而後將整個表達式轉換成數值:
好的,咱們繼續把他們結合在一塊兒來獲得字母「 a 」:
有趣!
因此,咱們利用上述字符的一些簡單組合就能夠獲得「 true 」和「 false 」中的字母,好比「 t 」「 r 」「 u 」「 e 」「 f 」「 a 」「 l 」「 s 」。那麼咱們能夠獲得其餘字母嗎?
固然,咱們能夠經過「 [ 」「 ] 」的簡單組合來獲得「undefined」,也就是說利用剛提到的黃金法則,咱們又獲得了「 d 」「 i 」「 n 」三個字母。
目前爲止,咱們用已得到的字母就能夠拼出「 fill 」「 filter 」 和「 find 」單詞,固然還有一些其餘的單詞。但還需注意, 這些單詞都具備數組的方法。這意味着他們是數組對象的一部分,能夠直接調用數組實例,如:[2,1].sort()。
如今,咱們要了解 JavaScript 另外一個重要特性:一個對象的屬性能夠經過點符號.或方括號[]訪問。上述數組方法是數組對象自己的屬性,咱們可使用方括號代替點,來調用這些方法。
因此說 [2,1]["sort"]() 和 [2,1].sort() 是等效的。
來讓咱們繼續深刻嘗試,看看用數組方法調用還會發生什麼。咱們能夠試着用剛纔獲得的字母拼寫出單詞,並將這些單詞做爲方法調用。看下面的例子:
這樣會獲得:
咱們能夠再次使用咱們的黃金法則,將這個方法頭轉換爲字符串:
到目前爲止,咱們就又獲得了「c」「o」「v」「(」「)」「{」「}」「[」「]」這些字母或者符號。
因爲咱們新得到了「c」和「o」兩個字母,就能夠和之前的字母組合成「constructor」(構造函數)單詞。
constructor 方法被全部 JavaScript 對象所共有,並且它會返回構建該對象的函數。
接下來讓咱們把已經獲得的對象的構造函數,以字符串形式展示出來:
這樣一來,咱們又獲得了「B」「N」「S」「A」「m」「g」「y」這些字母,咱們把它們添加到咱們的『字母庫』。如今咱們能夠用字母庫中的字母,構造一個可用方括號的函數「toString」。
咱們能夠這樣調用它:
咱們已經能夠利用黃金法則,將任何咱們想要的東西轉換成字符串。但咱們要怎麼使用呢?
好的,我如今告訴你,「Number」類型的「toString」方法有一個稱爲「radix」(基數)的祕密的論點。它規定一個數值在轉換爲字符串以前先進行基數換算,像這樣:
可是爲何基數最大爲16?正常來講最大爲36。但這樣一來,咱們就獲得了包括從「 0 - 9 」和「 a - z 」全部數字和字符。
幹得漂亮!
可是其餘的字符該怎麼辦呢?好比標點字符和大寫字符?咱們接着向下摸索!
因爲你的 JavaScript 代碼執行環境不一樣,不能肯定它是否能夠成功訪問到你預約義的對象或數組。若是你在瀏覽器中執行,它可能會訪問到遺留的 HTML包裝器方法。
比方說,「bold」是一個包裝在 <b> 標籤中的字符串方法。
這樣一來,咱們又獲得了「 < 」「 > 」和「 / 」字符。
可能你之前據說過「escape」函數。它主要做用是將一個字符串,轉換成一種瀏覽器友好的 URL 格式,而且可以被常見的瀏覽器識別和解析。
爲了達成最終目標,這個函數的功能十分重要,因此咱們要努力實現併合理利用它。咱們雖然能用「字母庫」中的字母拼寫出「escape」單詞,但咱們該如何將它真正的執行出來?
「escape」是一個全局做用域下的函數,就是說它不屬於咱們目前爲止處理過的任何函數類型。
那麼任意函數的構造函數是什麼呢?
答案是:「 function Function() { [native code] } 」。
利用這一點,咱們能經過一串代碼來構造一個實際功能的函數。
也能獲得:
咱們只需在結束執行時彈出「 ( ) 」,就能夠當即調用並執行「 alert 」函數。
是的,咱們如今能夠編譯執行字符串構成的代碼了。
因此接下來,咱們像下面所示,使用「 escape 」函數:
若是咱們在「 escape 」函數中傳入「 < 」字符,咱們會獲得「 %3C 」。哈哈,這樣咱們又獲得了字母「 C 」,若是你想拼出咱們缺乏的其餘單詞,那麼「 C 」字母是很是必要的。
利用字母「 C 」,咱們能夠寫出「 fromCharCode 」函數了,這個函數的功能是將咱們給定的十進制數轉換爲「 Unicode 」碼。它是「 String 」對象的一部分,像咱們之前同樣,調用它的構造函數獲得咱們所需的字符:
咱們利用 「 Unicode Lookup: convert special characters 」工具可以很容易地找到任何字符的十進制表示形式。
嘿,夥計!咱們終於大功告成!
如今,咱們可以只用這六個字符獲取任何一個其餘字符,咱們能將他們拼接起來,拼接出一行行代碼,咱們也能成功執行它們。
這意味着在 JavaScript 中,咱們僅僅用「 [ 」「 ] 」「 ( 」「 ) 」「 + 」和「 ! 」六個字符,就能夠完成 圖靈完備測試( Turing completeness )!!
你想證明一下?在你的控制檯中運行文章最後的代碼吧~
這幾個字符有很大做用嗎?
事實並不是如此,不久前 eBay 網利用這些作了一些很差的事情,它容許一些賣家將這些字符以某種形式嵌入店鋪主頁的 JavaScript 代碼中,並執行它們,這是一個至關罕見的攻擊方式。
一些人可能會提到代碼混淆,但事實上,這將是一種更好的代碼混淆方式。