选取文档元素的API


除了现在常用的选取API
1 document.getElementById()
2 document.getElementsByName()
3 document.getElementsByTagName()
4 ...

 新增的API 主要是
  document.querySelector('div>ul')
  document.querySelectorAll('div>ul>li')
     这两个API的强大之处在于能像CSS选择器一样选择元素,和Jquery的选择器有的一拼

<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title></title>
</head>
<body>
<div>
<ul>
<li></li>
<li class="abc"></li>
<li class="bbb abc"></li>
</ul>
</div>
<div>
<p>11111111111111
</p>
</div>
</body>
<script>
var a=document.querySelectorAll('div>ul')[0]
console.log(a.childElementCount) // 3
var b=document.createElement('li');
b.textContent='44444';
a.appendChild(b)
    console.log(a.childElementCount) //3
console.log(document.querySelectorAll('div>ul>li').length) //4
</script>
</html>


以下介绍下他们的不同点:
    document.querySelector()
        返回的是第一个匹配的元素(以文档顺序)
        匹配不到则返回null
   document.querySelectorAll()
       返回的是一个表示文档中匹配选择器的所有元素的NodeList对象(显然该对象是一个集合),
       这个NodeList对象并不是实时的:它包含在调用时刻选择器锁匹配的元素,但并不更新后续文档的变化(详见上面实列)
       匹配不到则返回一个空的NodeList对象
      选择器非法 将抛出异常
另外一点是这两个方法在Element节点中也有定义 (DocumentFragment节点上也是有定义的)
如:

     var d=document.getElementsByTagName('div')[0].querySelector('.abc')
     console.log(d.textContent)

目前支持这两个API 有:IE8+,Firefox 3.5+,Safari 3.1+,Chrom 和Opera 10+

有一个小问题:
    <div id="abcdefg">
                <p>11111111111111
               </p>
    </div>
     var c=document.querySelector('#abcdefg');
     console.log(c.querySelector('div p').innerHTML); // 这个是能找到值的
   理想情况是 在id为abcdefg 的内部查找 div 下面的p元素,显示出p的innerHTML 应该是找不到的
   但是现在却打印出来了 It's a problem; 查询时也必要这样查询
   应该一次性写出来: document.querySelector('#abcdefg div p'); 会报异常 因为找不到

 

性能问题:

       通过对1千万次的读取发现getElementBy系列的查询速度要远高与 queryselector系列

 

 1  var begin = new Date();
 2     for (var i = 0; i < 10000000; i++) {
 3 
 4         var a=document.getElementById('abc');
 5 
 6     }
 7     var end= new Date();
 8     console.log(end-begin);
 9     var begin1 = new Date();
10     for (var i = 0; i < 10000000; i++) {
11 
12         var a=document.querySelector('#abc');
13 
14     }
15     var end1=new  Date();
16     console.log(end1-begin1);

   究其原因发现 主要是因为queryselectorall  返回的nodeList是静态的 而getElementBy 系列返回的是动态的  细化一下主要是:

         在深入了解细节之前,首先说下这俩个方法重要的区别,不仅仅是一个方法接受tagName,另外一个接受css选择器。最重要的区别在于返回值: getElementsByTagName() 返回一个实时的 NodeList,
querySelectorAll()返回静态的 NodeList。 这点是对理解速度的快慢是非常重要的。实时的NodeList 这个是文档对象模型(Document Object Model)的一个坑。 NodeList对象(也就是在HTML DOM中的HTMLCollection对象)是个特殊的类型。DOM3手册对HTMLCollection对象的规定如下:

        Nodelist跟NamedNodeMap对象在DOM中是实时的;也就是说,对基本文档结构的修改,会被映射到相关的Nodelist跟NameNodeMap对象。例如,如果一个DOM的用户得到了包含有子元素节点的NodeList对象,随后在这个元素上添加更多的子节点(或者是移除,或者是修改他们),这些改变会自动映射到NodeList对象中,不需要用户部分的额外操作。同样的,改变在树中的节点,也会自动映射到跟这个节点有关的
NodeList跟NamedNodeMap中的对象。
getElementsByTagName()方法,返回这些实时的元素集合-随着文档的改变而更新。因此,下边这段代码其实是个死循环:

 1 var divs = document.getElementsByTagName("div"),
 2 i=0;
 3 while(i < divs.length){
 4 document.body.appendChild(document.createElement("div"));
 5 i++;
 6 }

因为divs.lenght实时计算的原因,所以这是个死循环。每次迭代,添加一个新的div,意味着divs.length每次循环都会增加。

这些实时的集合,看起来像个坏主意,但是他们被放到document.images,document.forms这些方法中,跟其他的一些pre-DOM的集合中使用相同的对象,在浏览器中非常常见。

  静态的NodeList
        querySelectorAll()返回的是静态的NodeList,描述如下:被querySelectorAll() 返回的对象必须(must)是静态的,非实时的([DOM-LEVEL-3-CORE],1.1.1部分)。后来的对文档的改变,不能(must not)反应到NodeList对象上。这意味着,此对象实际上包含的是文档刚创建的时候,查询到的匹配的列表。所以,即使querySelectorAll()的返回值跟表现,同getElementsByTagName()是一样的,但是实际上,他们是不同的。在前者中,NodeList实际上是一个文档状态,在方法被调用时刻的快照,后者总是会更新到当前的状态。所以,下边的代码不是死循环:

 1 var divs = document.querySelectorAll("div"),
 2 i=0;
 3 while(i < divs.length){
 4 document.body.appendChild(document.createElement("div"));
 5 i++;
 6 }

div.length 不会改变。

   So为啥是实时的NodeLists更快呢?
       实时的NodeLit对象能够快速的被浏览器创建,并返回,因为他们他们不必知道从开始到现在的数据信息,但是,静态的需要收集这些信息。再此强调下,WebKit的源码对两中类型的NodeList有独立的文件:DynamicNodeList.css跟StaticNodeList.cspp.两种类型的对象以不同的方式被创建。DynamicNodelist是被注册到缓存中。本质上,创建DynamicNodelist开销是比较小的,因为他不会之前的事情。无论何时DynamicNodeList被访问的时候,它必须查询文档的改变,作为length属性跟item()方法的结果跟StaticNodeList比较,在另外一个文件中实例被创建,然后用内部的一个循环,进行数据填充。之前文档查询的开销比使用”DynamicNodeList”实例大的多。如果你看一下WebKit的源码,创建querySelectorAll()的返回值的时候,都是使用循环去创建这个结果。

  结论:
     getElementsByTagName()比querySelectorAll()快的原因是,实时跟静态NodeList对象引起的。
     决定使用哪个方法,主要取决于你想要什么。如果你通过tagName搜索元素,不需要快照,应该使用getElementsByTagName();如果你需要一个快照结果,或者是做一个更复杂的css查询,应当使用
**querySelectorAll()*

    注,部分文档摘录自:

      http://www.cnblogs.com/dolphinX/p/3354318.html

        http://www.heyria.com/index.php/2014/06/why-is-getelementsbytagname-faster-that-queryselectorall/

 







 



     

  
posted @ 2016-04-14 09:19  Arthur007  阅读(222)  评论(0编辑  收藏  举报