本来这应该是最简单的事情,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;
};
目前还不知道有没有疏漏。
新闻热点
疑难解答