下午寫了篇最短地址欄載入指令碼的文章。不過再怎麼短仍然沒什麼意思,純屬娛樂下罷了。剛才想起能縮短個平時經常用到的代碼就好了,於是現在一邊寫一邊來研究,最短的XMLHTTP組建建立。
假如你的指令碼只針對某個瀏覽器開發,那麼建立XMLHTTP是很簡單的一件事,用XMLHttpRequest或者ActiveXObject即可。但事實上絕大多數的時候,我們都要考慮相容,於是我們通常寫成:
var x;
if(window.ActiveXObject)
x = new ActiveXObject("Microsoft.XMLHTTP");
else
x = new XMLHttpRequest();
當然,熟練的朋友更傾向於簡練的代碼:
var x = window.ActiveXObject?
new ActiveXObject("Microsoft.XMLHTTP"):
new XMLHttpRequest();
但也到此而已。這段代碼還能繼續壓縮嗎?我們不妨來探索下。
現在我們把一堆單詞: ActiveXObject, "Microsoft.XMLHTTP", XMLHttpRequest, window 配上幾個符號重新排列起來,組合出一個文法正確並且能正常啟動並執行運算式。
首先我們最容易想到的就是共用一個new。因為JS裡面有個很強大的運算子“||”,相信大家都用過。所以我們先用||得出Class,然後用new執行個體化出instance。於是:
new (window.XMLHttpRequest || ActiveXObject("Microsoft.XMLHTTP"))
很不幸,它沒能通過IE6,7的考驗。(IE8+已經支援XMLHttpRequest了)
錯誤很簡單,就在ActiveXObject("Microsoft.XMLHTTP")上。Automation 伺服器不能建立對象。
在IE裡,ActiveXObject(...)之前必須帶上new,否則就會出現上面的錯誤。但請注意了,ActiveXObject後面是帶參數調用的。如果我們單獨引用ActiveXObject這個函數,然後再執行個體化,結果會如果呢?我們測試下:
var ref = ActiveXObject;
var x = new ref("Microsoft.XMLHTTP");
x.open("GET", "1.html", true);
x.send();
alert(x.responseText)
結果不但沒有報錯,並且成功的顯示出了文字。這說明window.ActiveXObject這個方法是可以引用調用,但必須用new才能建立組建。這很好理解:function ActiveXObject(){}的Native Code會判斷當前是new call還是direct call,如果不是new call就報錯。這意味著你不能預先建立出XMLHTTP的Class,而必須用ActiveXObject的工廠形式。
既然事實如此,我們只能用XMLHttpRequest || ActiveXObject這樣的邏輯。如果帶上new,我們就得到這樣的代碼:
new (window.XMLHttpRequest || ActiveXObject)
這對XHR的建立已經夠了,但是ActiveX還需要提供一個參數指定組件名。這個參數加在哪裡好呢?不用多慮,就放在最後!
因為XMLHttpRequest的建構函式是不帶參數的,而JS是個弱類型語言,所以你即便給他指定一個參數也不會出問題。於是最後,我們用一行運算式即可建立:
new (window.XMLHttpRequest || ActiveXObject)("Microsoft.XMLHTTP")
因為IE8+即支援 XMLHttpRequest 和 ActiveXObject,因此上面 || 左右順序決定了IE8+優先使用哪種。
不過,這還不是最簡短的!沒錯,還有更精簡的,但顯得不是特別正規,甚至有點晦澀。
縱觀上述代碼,其中的window顯得有點多餘,但又不能去掉。假如有個簡單的辦法判斷是(或者不是)IE瀏覽器,我們就可以用 ?: 運算子來代替 || 了。
曾經有個老外寫過最簡短判斷IE的辦法,只需6個位元組 !-[1,] 原理就是IE特有的特徵,數組處理最後項的bug。利用這個辦法,我們還可以進一步壓縮代碼:
new(-[1,]?XMLHttpRequest:ActiveXObject)("Microsoft.XMLHTTP")
無疑,這是最簡短的XMLHTTP建立代碼了!正好60個位元組。 但相比規範性和可讀性,還是推薦之前那種。
補充:感謝經典論壇上的crimsonet網友提醒,其實用self對象完全可以代替window。self是window的唯讀屬性,並且永遠指向window,所以用:
new(self.XMLHttpRequest||ActiveXObject)("Microsoft.XMLHTTP")
也正好是60位元組,並且更規範:)
(如果不是在內嵌架構裡啟動並執行話,top===window,還能-1。在架構內top引用頂層表單,當然會有問題的了)