【分享】深入挖掘document.getElementsByTagName()方法的返回值

WebAdvocate 2010-07-06 02:22:00
加精
最近天气好热,一只蚊子落到了我身上,被烫死了,悲天悯人的我太伤心了……
天气虽然炎热,但工作依然不能停歇,整日在代码堆里摸爬滚打,却不见救世主降临,来赐我一个和谐的浏览器世界。OMG,生命不止,兼容问题不歇。无论我活着,还是我死了,我都会在兼容性问题堆里,吹着嗡嗡的祖拉嗡嗡的飞来飞去。
前些日子,碰到过一个比较麻烦的问题。想从 document.getElementsByTagName()方法的返回值中取出某个特定的元素。一开始以为它的返回值是一个数组,结果,大错特错。它返回的是一个 DOM 对象,可以遍历,有 length 属性,但不是数组。
证据在这里:
<script>
window.onload = function() {
var divs = document.getElementsByTagName("div");
document.getElementById("info").innerHTML = !!(divs instanceof Array);
}
</script>
<div></div>
<div id="info"></div>

把它当Array用的兄弟姐妹小心了。
既然不是Array,那么它到底是什么呢?
继续探索之:
<script>
window.onload = function() {
var divs = document.getElementsByTagName("div");
document.getElementById("info").innerHTML = Object.prototype.toString.call(divs);
}
</script>
<div></div>
<div id="info"></div>

在各浏览器中打开:
IE: [object Object]
Firefox:[object HTMLCollection]
Chrome/Safari /Opera:[object NodeList]

这个结果让人很纠结,5 个浏览器3种结果,其中 IE 和Firefox貌似不太合群。
无奈,干脆去查查标准。

W3C DOM3中 document.getElementsByTagName() 方法的返回值

getElementsByTagName() 是 W3C 从 DOM1就引进的获取拥有相同标签名称的一组元素的方法。而在 DOM2 和 DOM3 保留了这个接口。
它的返回值是一个 NodeList。
一下是它的接口说明:
interface Element : Node {
...
NodeList getElementsByTagName(in DOMString name);
...
}

DOM3中关于 getElementsByTagName接口的详细说明,请看这里:getElementsByTagName

主流浏览器中 getElementsByTagName()方法的返回值

各浏览器官方文档中对于此方法的说明也符合W3C的规定,都是返回的 NodeList类型的对象集合。
看来,Firefox跟自己矛盾了,哈哈。
关于资料,看这里
Mozilla 官方:document.getElementsByName
Safari官方 Webkit DOM:getElementsByName
MSDN官方: getElementsByName Method
那么什么是NodeList接口呢,它又有什么特性呢,接着往下看。

NodeList 接口

W3C DOM3规定,NodeList是一个有序的节点集合。

它的属性和方法:
NodeList . length
返回集合中的对象个数。length是只读属性。
Node = NodeList . item(index)
从集合中返回指定索引的节点。


可见,NodeList类型的对象可以使用 item()方法获取其中的节点。
在 Firefox,Chrome和Safari中,对于NodeList的定义与 W3C相同。
在 IE中,NodeList继承了Collection接口,所以,NodeList对象支持Collection接口中的方法。
Opera 没有找到相关说明。
关于 NodeList的说明资料:
W3C DOM3: Interface NodeList
Mozilla: NodeList
Safari官方Webkit DOM: NodeList
MSDN NodeList接口:NodeList Class
下面开始介绍,如何

从 document.getElementsByTagName()方法的返回值中取值

汇总表:

注:
1. 红色代表不支持,绿色代表支持。
2. 对于 NodeList[name]、NodeList(name) 和 NodeList.namedItem(name)这 3行,IE的支持情况跟其他支持该方式的浏览器之间也存在差异,当document,getElementsByTagName()的返回值中存在相同 name 的元素时,IE返回一组元素,而其他支持的浏览器只返回符合的第一个元素。


可见,在IE和Opera 中,getElementsByTagName()返回值更像一个HTMLcollection;而在Firefox中,介于HTMLcollection和 NodeList之间。

NodeList[index]和 NodeList[id]

代码:
<script type="text/javascript">
window.onload = function() {
var spans = document.getElementsByTagName("span");
var span2 = spans[1];
var span3 = spans["span3"];
document.getElementById("info").innerHTML = "<br/>NodeList[index].id : " + span2.id
+ "<br/>NodeList[id].id : " + span3.id;
}
</script>
<span id="span1"></span>
<span id="span2"></span>
<span id="span3"></span>

<div id="info"></div>

测试结果在各浏览器中都相同:
NodeList[index].id : span2
NodeList[name].id : span3


NodeList[name]

测试代码:
<script type="text/javascript">
window.onload = function() {
var inputs = document.getElementsByTagName("input");
var input_1 = inputs["input1"];
document.getElementById("info").innerHTML += "<br/>NodeList[name].id : " + input_1.id;
}
</script>
<input id="ipt1" name="input1">
<input id="ipt2" name="input2">
<input id="ipt3" name="input3">

<div id="info"></div>

结果:
Firefox、Opera和IE,都输出的是:NodeList[name].id : ipt1
Chrome 和Safari报错,它们不支持这种方式。

另外,Firefox和Opera中,此方法存在差异,因为 name 属性可以相同,当存在多个相同 name 的元素时,Firefox和Opera中取出的还是第一个,而IE取出的则是一个组。
看代码:
<script type="text/javascript">
window.onload = function() {
var inputs = document.getElementsByTagName("input");
var input_1 = inputs["input1"];
document.getElementById("info").innerHTML += "NodeList[name].id : " + input_1.id+
"<br/>NodeList[name].length : " + input_1.length;
}
</script>
<input id="ipt1" name="input1">
<input id="ipt2" name="input1">
<input id="ipt3" name="input3">

<div id="info"></div>

在Firefox和Opera中输出:
NodeList[name].id : ipt1
NodeList[name].length : undefined

IE 中:
NodeList[name].id : undefined
NodeList[name].length : 2



NodeList(index)

测试用例代码:
<script type="text/javascript">
window.onload = function() {
var spans = document.getElementsByTagName("span");
try {
var span2 = spans(1);
document.getElementById("info").innerHTML = "NodeList(index).id: " + span2.id;
} catch(err) {
document.getElementById("info").innerHTML = "NodeList(index) : " + err;
}
}
</script>
<span id="span1"></span>
<span id="span2"></span>

<div id="info"></div>

以上代码,只有在Firefox中报错:TypeError: spans is not a function
其他浏览器中的输出:NodeList(index).id: span2


NodeList(id)

测试代码:
<script type="text/javascript">
window.onload = function() {
var spans = document.getElementsByTagName("span");
try {
var span2 = spans("span2");
document.getElementById("info").innerHTML = "NodeList(id).id: " + span2.id;
} catch(err) {
document.getElementById("info").innerHTML = "NodeList(id) : " + err;
}
}
</script>
<span id="span1"></span>
<span id="span2"></span>

<div id="info"></div>

Firefox、 Chrome和Safari报错,IE 和 Opera 依然支持。

NodeList(name)

看测试用例代码:
<script type="text/javascript">
window.onload = function() {
var inputs = document.getElementsByTagName("input");
var input_1 = inputs("input1");
document.getElementById("info").innerHTML += "NodeList(name).id : " + input_1.id+
"<br/>NodeList(name).length : " + input_1.length;
}
</script>
<input id="ipt1" name="input1">
<input id="ipt2" name="input1">
<input id="ipt3" name="input3">

<div id="info"></div>

以上代码,IE和Opera都支持。但是,支持情况也有差异,同 NodeList[name]。
Firefox和Webkit浏览器都不支持。

NodeList.item(index)

看测试用例代码:
<script type="text/javascript">
window.onload = function() {
var spans = document.getElementsByTagName("span");
try {
var span2 = spans.item(1);
document.getElementById("info").innerHTML = "NodeList.item(idx).id: " + span2.id;
} catch(err) {
document.getElementById("info").innerHTML = "NodeList.item(idx) : " + err;
}
}
</script>
<span id="span1"></span>
<span id="span2"></span>

<div id="info"></div>

经过测试,各浏览器都支持这种方式。

NodeList.namedItem(id)

测试用例代码:
<script type="text/javascript">
window.onload = function() {
var spans = document.getElementsByTagName("span");
try {
var span2 = spans.namedItem("span2");
document.getElementById("info").innerHTML = "NodeList.namedItem(name).id: " + span2.id;
} catch(err) {
document.getElementById("info").innerHTML = "NodeList.namedItem(name) : " + err;
}
}
</script>
<span id="span1"></span>
<span id="span2"></span>

<div id="info"></div>

Chrome和Safari不支持此方法,报错。
其他浏览器输出:NodeList.namedItem(id).id: span2

NodeList.namedItem(name)

测试用例代码:
<script type="text/javascript">
window.onload = function() {
var inputs = document.getElementsByTagName("input");
var input_1 = inputs.namedItem("input1");
document.getElementById("info").innerHTML += "inputs.namedItem(name).id : " + input_1.id+
"<br/>inputs.namedItem(name).length : " + input_1.length;
}
</script>
<input id="ipt1" name="input1">
<input id="ipt2" name="input1">
<input id="ipt3" name="input3">

<div id="info"></div>

Chrome 和 Safari 不支持这个方法。
Firefox、 Opera和IE都支持,但存在差异,情况跟NodeList[name]相同。

使用document.getElementsByTagName()的误差

在利用getElementsByTagName()方法取同一类对象时,浏览器插件生成的标签也会被计算在内。例如,在document.getElementsByTagName("div")的返回值中,包括Firebug插件的div标签。所以,如果利用index取值,可能会跟预想的结果不同。

总结

这个方法真不让人省心啊,既然兼容性问题这么多,那么,应该怎样避免此类问题的发生呢?其实,很简单,用上面表里,所有浏览器都支持的方法就好。少用 index 取元素,不够准确。另外,没有特殊需求而仅仅为了获取元素,请使用document.getElmentById()。
...全文
160019 110 打赏 收藏 转发到动态 举报
写回复
用AI写文章
110 条回复
切换为时间正序
请发表友善的回复…
发表回复
goden2009 2011-09-17
  • 打赏
  • 举报
回复
楼主辛苦,看到不少好东西
Milk- 2010-09-14
  • 打赏
  • 举报
回复
学习,山高水长,奋斗不止。
zc_china 2010-08-29
  • 打赏
  • 举报
回复
好贴 顶起 谢谢分享~~
lxjtsoftware 2010-08-12
  • 打赏
  • 举报
回复
楼主太有才了,顶一个
tingfjm 2010-08-12
  • 打赏
  • 举报
回复
哎,整天用框架了。基础的都给忘了。。。
五谷杂粮_007 2010-08-11
  • 打赏
  • 举报
回复
貌似用JQUERY的
$("input")可以解决这个问题
daishunbin_2010 2010-07-28
  • 打赏
  • 举报
回复
写太深了,看不懂
hichanghuan 2010-07-21
  • 打赏
  • 举报
回复
看lz辛苦的
jaoooo 2010-07-14
  • 打赏
  • 举报
回复
赞美一个
xfjylimeng 2010-07-12
  • 打赏
  • 举报
回复
哥用jquery,谁知道里边怎么处理的。哎。
WebAdvocate 2010-07-11
  • 打赏
  • 举报
回复
[Quote=引用 95 楼 woshiguozhongbin 的回复:]

引用 69 楼 sethackpro 的回复:

楼主的开始的旁白蛮有才的

的确....
[/Quote]多谢69楼和95楼的同学:)
  • 打赏
  • 举报
回复
哎,整天用框架了。基础的都给忘了。。。
cejay 2010-07-11
  • 打赏
  • 举报
回复
来学习了
Abin-2008 2010-07-10
  • 打赏
  • 举报
回复
[Quote=引用 69 楼 sethackpro 的回复:]

楼主的开始的旁白蛮有才的
[/Quote]
的确....
lmc158 2010-07-10
  • 打赏
  • 举报
回复
<script type="text/javascript">
window.onload = function() {
var inputs = document.getElementsByTagName("input");
var input_1 = inputs("input1");
document.getElementById("info").innerHTML += "NodeList(name).id : " + input_1.id+
"<br/>NodeList(name).length : " + input_1.length;
}
</script>
<input id="ipt1" name="input1">
<input id="ipt2" name="input1">
<input id="ipt3" name="input3">

<div id="info"></div>
inmyownsky1 2010-07-10
  • 打赏
  • 举报
回复
up一下
haoyizsw 2010-07-09
  • 打赏
  • 举报
回复
好东西啊
niuxqd 2010-07-09
  • 打赏
  • 举报
回复
向你致敬!
zhouxianglh 2010-07-09
  • 打赏
  • 举报
回复
楼主纠结啊
jackingod 2010-07-09
  • 打赏
  • 举报
回复
研究得真够透彻啦! 赞!
加载更多回复(85)

5,006

社区成员

发帖
与我相关
我的任务
社区描述
解读Web 标准、分析和讨论实际问题、推动网络标准化发展和跨浏览器开发进程,解决各种兼容性问题。
社区管理员
  • 跨浏览器开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧