JS做爲一門如此靈活的語言,天然在編碼時給咱們帶來了不少方便,但方便的同時,也衍生出了不少變態的語法,下面咱們來梳理一些常見的變態語法,但願你下次在某位大牛的代碼中看到這樣的東西,不要驚掉下巴。java
NO.1bootstrap
——————————————————————————————————————數組
Number.prototype.add = function(n){瀏覽器
return this+n;函數
}測試
2"add"
——————————————————————————————————————this
最後一句話是什麼玩意兒?好像沒看懂呢? 咱們來運行一下看看編碼
我擦? 它竟然執行了?結果是5,看上去彷佛對2和3作了加法。prototype
不是說變量名不能數字開頭麼?這是怎麼回事?瀏覽器抽風了?對象
實際上js有不少不能說的祕密,其中一個就叫作自動裝箱,這是引用java裏的叫法。也就是說,當咱們試圖2[「add」]的時候,這個數字2已經再也不是2了,它被自動轉換成了Number對象,跟java中的包裝類型是一個意思。
等價於這樣寫:
new Number(2)
而對象是能夠經過[「prop"]這種形式來獲取屬性的,因而咱們就不難推理了
2["add"] 至關於 new Number(2).add
最終變成
new Number(2).add(3);
結果是 5
NO.2
—————————————————————————————————————— +function(){;}()
——————————————————————————————————————
這又是個什麼玩意兒?函數前面帶個+號? 這難道是自動類型轉換?等等,裏面是個;號? 後面還有一對( )?
先不要着急驚訝,其實還有不少,例如:
-function(){;}()
!function(){;}()
~function(){;}()
void function(){;}()
new function(){;}()
delete function(){;}()
var i = function(){;}()
1 && function(){;}()
0 || function(){;}()
1 & function(){;}()
1 | function(){;}()
1 ^ function(){;}()
1, function(){;}()
我靠!這些喪盡天良的寫法是誰發明的?!你給我站出來,我保證不打死你!
(此處做者冷靜了5分鐘)
接下來講說它的原理吧
首先 ;號自己也是一條語句,相信大多數同窗應該是知道的,就很少說了。其次,一個函數的自調用,若是寫成這樣:
錯誤的緣由在於,函數聲明和函數調用是不能夠混在一塊兒的,因此一般的寫法是:
這並非把函數當成了一個總體來運行,這裏其實還有一個不能說的祕密
( )這個符號,在js裏是運算符。(A)的結果是返回表達式A
因此它的出現,讓這個匿名函數從聲明變成了執行,也就是編譯期間瀏覽器不會提早準備它,天然就沒有語法錯誤。而5分鐘前咱們看到的那些喪心病狂的寫法,其實原理都同樣,經過運算符把聲明變成執行。固然這些符號都不會影響函數的正常執行結果。
可是問題又來了,這種泯滅人性的寫法,如今竟然還挺常見的,例如:
沒錯,這就是著名的bootstrap的js源碼,連它都是這麼寫的,莫非真有什麼好處?
經過在網上查詢大量的資料,我還真發現有人專門對此作了研究,將上面這些寫法所有在各個瀏覽器中間作了壓力測試,發現+function( ){;}( ) 執行速度最快,比(function( ){})( )要快出好幾倍
而 new function( ){;}( ) 執行速度最慢。
不過爲了追求效率而把代碼寫成這樣到底值不值,那隻能你本身去判斷了。
NO.3
——————————————————————————————————————
!!a
——————————————————————————————————————
這又是什麼鬼啊
!!a 實際上等價於 a || false
因爲js中全部的內容都是能夠跟布爾類型互換的,這也是js特別讓人費解的地方,好比
if(window.VBArray){…}
能夠用來判斷IE瀏覽器,由於對象存在時,等價於true,undefined等價於false,可是!不少時候咱們判斷一個屬性是否存在,並不須要立刻做出反應,而是將結果告知他人,好比說有個函數,test(hasSuperman),函數規定調用時須要傳入一個布爾類型,告知它superman是否存在,你可能會這樣寫:
if(window.superman){
test(true);
} else {
test(false);
}
但你最好不要這麼寫:
test(window.superman);
由於你並不知道test函數內部發生了什麼,因此很難預料會不會產生錯誤,所以最好的寫法是這樣:
test(!!window.superman);
經過兩次取反,保證了值沒有變化,但類型已經被轉爲了布爾類型。好吧,彷佛這麼寫還有點道理。
NO.4 最短IE(6,7,8)斷定
————————————————————————————————————— if(!-[1,]){
//判斷IE6,7,8
}
—————————————————————————————————————
它的原理其實是利用了IE的bug。
當咱們寫下一個數組 [1,].length
在IE中 [1,].length -------> 2
在非IE中 [1,].length -------> 1
當咱們試圖打印[1,],至關於調用toString()方法
在IE中 [1,] -------> "1,"
在非IE中 [1,] -------> "1"
當咱們給它加上負號-[1,]
在IE中 -[1,] -------> NaN
在非IE中 -[1,] -------> -1
當咱們對它進行取反!-[1,]
在IE中 !-[1,] -------> true
在非IE中 !-[1,] -------> false
這樣咱們就能夠判斷是否爲IE瀏覽器了,這個bug一直到IE9以後才消失的。
好了,此次的變態語法就先講這麼多,之後碰到更新鮮的再來給你們更新,拜拜。