HTML集合是用于存放DOM节点引用的类数组对象。下列方法的返回值都是一个集合:
❑document.getElementsByName
❑document.getElementsByClassName
❑document.getElementsByTagName_r
下列属性也属于HTML集合:
❑document.images:页面中所有的<img>元素。
❑document.links:所有的<a>元素。
❑document.forms:所有表单。
❑document.forms[0].elements:页面中第一个表单的所有字段。
这些方法和属性返回HTMLCollection对象,是一种类似数组的列表。它不是数组,因为它没有数组的方法,比如push、slice等,但它提供了一个length属性,与数组一样可以使用索引访问列表中的元素。例如,document.images[1]返回集合中的第二个元素。正如DOM标准中所定义的那样,HTML集合是一个虚拟存在,意味着当底层文档更新时它将自动更新。
HTML集合实际上在查询文档,当更新信息时,每次都要重复执行这种查询操作。例如,读取集合中元素的数目,也就是集合的length。这正是执行低效率的原因。
var allps=document.getElementsByTagName_r('p');
for(var i=0;i<allps.length;i++){
document.body.appendChild(document.createElement('p'))
}
上面这段代码看上去只是简单地增加了页面中p元素的数量:遍历现有p,每次创建一个新的p并附加到body上面。实际上这是个死循环,因为循环终止条件allps.length在每次迭代中都会增加,它反映出底层文档的当前状态。
像这样遍历HTML集合会导致逻辑错误,而且也很慢,因为每次迭代都需要进行查询,所以不建议用数组的length属性做循环判断条件。访问集合的length比数组的length还要慢,因为这意味着每次都要重新运行查询过程。在下面的例子中,将一个集合coll复制到数组arr中,然后比较每次迭代所用的时间。
function toArray(coll){
for(var i=0,a=,len=coll.length;i<len;i++){
a[i]=coll[i];
}
return a;
}
设置一个集合,并把它复制到一个数组:
var coll=document.getElementsByTagName_r('p');
var ar=toArray(coll);
比较下列两个函数:
//比较慢
function loopCollection{
for(var count=0;count<coll.length;count++){
}
}
//比较快
function loopCopiedArray{
for(var count=0;count<arr.length;count++){
}
}
当每次迭代过程访问集合的length属性时,将会导致集合器更新,在所有浏览器上都会产生明显的性能损失。优化的办法很简单,只要将集合的length属性缓存到一个变量中,然后在循环判断条件中使用这个变量。
function loopCacheLengthCollection{
var coll=document.getElementsByTagName_r('p'),
len=coll.length;
for(var count=0;count<len;count++){
}
}
上面函数的运行速度与loopCopiedArray一样快。
遍历数组比遍历集合快,如果先将集合元素复制到数组,访问它们的属性将更快。记住这需要一个额外的步骤——遍历集合,因此,应当评估在特定条件下使用这样一个数组副本是否有益。