本來這應該是最簡單的事情,javascript中提供了instanceof運算符,可以檢測某個變量是否某種類型的實例,一般情況下可以這樣檢測數組:testvar instanceof array == true。但是,在跨frame的時候,等式不成立。假設測試頁test.html的代碼如下:
<script language=”javascript” type=”text/javascript”>
//<![cdata[
function isarray(testvar) {
return testvar instanceof array;
}
//]]>
</script>
<iframe id=”testframe” src=”testframe.html”></iframe>
testframe.html的代碼如下:
<script language=”javascript” type=”text/javascript”>
//<![cdata[
function isarray(testvar) {
alert(parent.isarray([]));
}
//]]>
</script>
輸出的內容是false。似乎每個頁面都有自己的array類型,如果把isarray改寫一下,輸出的就是true:
function isarray(testvar) {
return testvar instanceof document.getelementbyid(”testframe”).contentwindow.array;
}
檢測testvar.constructor也會出現類似的情況。因此,這種方法不可行。
通過數組獨有的函數進行檢測,比如檢測testvar.sort是否未定義。這種方法在一般情況下也是可行的,但是健壯性不足。如果給testvar動態加了一個sort方法,判斷就會失誤。
沒什么好說的,直接看代碼,太牛了:
if (object.prototype.tostring.call(testvar) === “[object array]“) return 1;
所謂的集合就是可以通過下標訪問但又不是數組的類型。已知的javascript集合有兩種,一種是htmlcollection,另一種是函數的參數arguments。
在已知testvar不是數組的情況下,先檢測它的length屬性是否存在。包含length屬性的類型也不少,比如window、string、某些htmlelement。所以要檢測的特征非常多:
testvar.length != null &&
!testvar.alert && // 不是window
!testvar.charat && // 不是string
!testvar.nodetype // 不是htmlelement
由于其他情況實在太多,容易出現疏漏,所以最終還是沒有采取這種辦法。
已知的集合只有兩種,所以還是檢查這兩種集合的特性吧。htmlcollection有item方法,而arguments則有callee屬性:
if (testvar.item || testvar.callee) return 2;
這時,select元素開始攪局。它竟然包含htmlcollectiond的所有特性。于是,還是要判斷nodetype:
if (!testvar.nodetype && testvar.item || testvar.callee) return 2;
select元素被轟走了,萬惡的ie開始搗亂。首先是xml的問題,某個ajax回調函數:
function onsuccess(xhr) {
var xmldoc = xhr.responsetext;
alert(xmldoc.getelementsbytagname); // ie下報錯
var root = xmldoc.getelementsbytagname(”root”);
alert(root.item) // ie下報錯
}
也就是說,在ie下,只要嘗試檢測xml節點或xml節點集合的方法都會報錯。幸好還可以用typeof去對付它們。
function onsuccess(xhr) {
var xmldoc = xhr.responsetext;
alert(typeof(xmldoc.getelementsbytagname)); // ie下輸出”unknown”
var root = xmldoc.getelementsbytagname(”root”);
alert(typeof(root.item)) // ie下輸出”unknown”
}
因此,代碼就改成:
if (!testvar.nodetype && typeof testvar.item != “undefined” || testvar.callee) return 2;
其次,是window對象的問題:ie下的window對象也有item方法。所以還是要檢測window對象:
if (!testvar.nodetype && typeof testvar.item != “undefined” && !testvar.alert || testvar.callee) return 2;
雖然檢測特性容易出現失誤,但是目前也只有這種辦法了。
至此,終于折騰完,整個函數簡寫后就是:
var isarray = function(testvar) {
return object.prototype.tostring.call(testvar) === “[object array]” ? 1 : testvar.callee || (typeof testvar.item != “undefined” && !testvar.nodetype && !testvar.alert) ? 2 : 0;
};
目前還不知道有沒有疏漏。
新聞熱點
疑難解答