首页 » 编写高质量代码:改善JavaScript程序的188个建议 » 编写高质量代码:改善JavaScript程序的188个建议全文在线阅读

《编写高质量代码:改善JavaScript程序的188个建议》建议112:谨慎使用HTML集合

关灯直达底部

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一样快。

遍历数组比遍历集合快,如果先将集合元素复制到数组,访问它们的属性将更快。记住这需要一个额外的步骤——遍历集合,因此,应当评估在特定条件下使用这样一个数组副本是否有益。