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

《编写高质量代码:改善JavaScript程序的188个建议》建议116:推荐使用CSS选择器

关灯直达底部

childNodes、firstChild和nextSibling属性是不区分元素节点和其他类型节点的,如注释节点和文本节点(这两个标签之间往往只是一些空格)。在许多情况下,只有元素节点会被访问,所以在循环中,似乎应当对节点返回类型进行检查,过滤出非元素节点。事实上,这些检查和过滤都是不必要的DOM操作。

目前许多浏览器提供了只返回元素节点的API函数,如果可用最好利用起来,因为写这些函数比在JavaScript中写过滤函数要快。

遍历children比遍历childNodes更快,因为集合项更少。HTML源码中的空格实际上是文本节点,它们不包括在children集合中。在所有浏览器中,children比childNodes更快,差别不是太大,通常只快1.5~3倍。特别值得注意的是,在IE中,遍历children明显快于遍历childNodes,在IE 6中快24倍,在IE 7中快124倍。

选择DOM元素经常需要更精细的控制,而不只是采用getElementById和getElementsByTagName_r之类的函数。有时结合这些函数调用并迭代操作它们返回的节点,以获取所需要的元素,这一精细的过程可能使效率降低。

另外,使用CSS选择器是一个便捷的确定节点的方法,这是因为大家已经对CSS很熟悉了。许多JavaScript库为此提供了API,而且最新的浏览器提供了一个名为querySelectorAll的原生浏览器DOM函数。显然这种方法比使用JavaScript和DOM迭代并缩小元素列表的方法要快。


var elements=document.querySelectorAll('#menu a');


elements的值将包含一个引用列表,指向那些具有id="menu"属性的元素。函数querySelectorAll接收一个CSS选择器字符串参数并返回一个NodeList(由符合条件的节点构成的类数组对象)。此函数不返回HTML集合,这就避免了HTML集合所固有的性能问题,以及潜在的逻辑问题。如果不使用querySelectorAll,达到同样目标的代码会冗长一些。


var elements=document.getElementById('menu').getElementsByTagName_r('a');


在这种情况下,elements将是一个HTML集合,要想得到与querySelectorAll同样的返回值类型,还需要将它复制到一个数组中。

当需要联合查询时,使用querySelectorAll更加便利。例如,在页面中,一些p元素的class名称是“warning”,另一些class名称是“notice”,可以用querySelectorAll一次性获得这两类节点。


var errs=document.querySelectorAll('p.warning,p.notice');


如果不使用querySelectorAll,那么获得同样列表需要更多工作。一个办法是选择所有的p元素,然后通过迭代操作过滤出那些不需要的单元。


var errs=,ps=document.getElementsByTagName_r('p'),classname='';

for(var i=0,len=ps.length;i<len;i++){

classname=ps[i].className;

if(classname==='notice'||classname==='warning'){

errs.push(ps[i]);

}

}


比较上面两种不同的用法,使用选择器querySelectorAll比使用getElementsByTagName_r的性能要好很多。因此,如果浏览器支持document.querySelectorAll,那么最好使用它。如果使用JavaScript库所提供的选择器API,那么确认一下该库是否确实使用了原生方法。如果不是,则需要将库升级到新版本。

还可以使用另一个函数querySelector获取节点,它可以返回符合查询条件的第一个节点。由于querySelectorAll和querySelector这两个函数都是DOM节点的属性,所以可以使用document.querySelector('.myclass')来查询整个文档中的节点,或者使用elref.querySelector('.myclass')在子树中进行查询,其中elref是一个DOM元素的引用。