静态NodeList 和 动态NodeList的区分

ps:相识这个知识点的缘由

前两天我在重温js dom编程的时刻,看到了猎取dom元素这一章,然后看到了getElementsByTagName()和getElementsByClassName(),以后又相识到了当代浏览器新出的一个DOM API–querySelectorAll().以我的性情,看到这些要领以后我肯定是想相识一下它们的差别点啦,所以我就翻阅材料,就看到了stackoverflow上面的一个问题

var temp = document.querySelectorAll(".class");
for (var i=0, max=temp.length; i<max; i++) { 
     temp[i].className = "new_class";
}

var temp = document.getElementsByClassName("class");
for (var i=0, max=temp.length; i<max; i++) { 
     temp[i].className = "new_class";
} 

运转上述这两段代码,假如猎取到的temp的长度都为3,那末第一段代码能将三个元素的className悉数变动成new_class”,而第二段代码只能讲第一个元素和第三个元素的className变动成”new_class”.这内里的缘由就是动态nodelist和静态nodelist的区分。
然后我又翻阅材料查找什么是动态nodelist,什么是静态nodelist。于是乎,就有了下面的长篇大论。

说说NodeList,HTMLCollection以及NamedNodeMap

在差别版本的浏览器中,假如挪用猎取多元素的DOM要领(getElement…()),有的会获得NodeList(多为旧浏览器),有的会获得HTMLCollection(多为新浏览器)。运用Node Interface的要领,如childNodes,获得的通常是NodeList,而运用其他Interface的要领,又有能够获得HTMLCollection。而NamedNodeMap又和前面二者返回的东西范例也不相同,所以有必要相识一下这三者的区分。

1. 三者的相同点

1.1 三者都具有length属性

1.2 三者都有item()要领

1.3 三个鸠合都是”动态的”,假如对NodeList和HTMLCollection中的元素举行操纵都邑直接反应到DOM中,因而假如一次性直接在鸠合中举行DOM操纵的话,开支异常大。(这会在解说动态的时刻细致诠释)

2. 三者的差别点

2.1 nodeList内里包括了一切的节点范例,比方元素节点,文本节点等

2.2 HTMLCollection内里只包括元素节点

<div>
    <!-- Comment -->
    <p>This is Some Text</p>
</div>

上面这段代码,假如作为NodeList返回,那末浏览器最多会给这个列表5个元素

1.一个<div>和解释间的断行和空格(或tab)作为text node(没错,标签之间的空缺标记也能够被剖析为text node

2.解释作为comment node

3.解释和<p>之间的断行和空格(或tab)作为text node,p作为element

4.</p></div>之间的断行和空格(或tab)作为text node

然则假如是作为HTMLCollection返回的话,那末就一个<p>元素这么简朴

2.3 NamedNodeMap内里包括了”Attribute”的鸠合,比方id,title,name等,鸠合中的每个元素都是attr范例。

2.4 三个鸠合所供应的要领也不相同,比方HTMLCollection中供应了namedItem(),而别的两个鸠合就没有供应这个要领

扩大点:

  1. item和namedItem都能够经由过程[]的缩写举行挪用,有的浏览器还支撑用()的缩写举行挪用(也就是能够list[index],list[key]或许list(index),list(key)),以及直接用dot notation挪用namedItem(比方list.key)

  2. IE8及以下版本浏览器中,解释属于HTMLCommentElement,算作Element,因而会出现在HTMLCollection里

  3. 我们能够用alert/console.log(document.getElement…)打印出来看下返回的是什么范例的鸠合,下面这个链接中讲的也算细致,能够参考下:http://www.jb51.net/article/2…

ps:以上知识点参考链接:

http://www.cnblogs.com/joyeec…,
http://stackoverflow.com/ques…,
http://stackoverflow.com/ques…

说了这么多,那末究竟什么是动态NodeList?什么是静态NodeList呢?它们之间有什么区分?

动态NodeList

上面我们说到NodeList,HTMLCollection以及NamedNodeMap都是动态的。也就是说,对底层文档构造的修正会动态地反应到相干的连系NodeList,HTMLCollection以及NamedNodeMap中。比方:假如先猎取了某个元素的子元素的动态鸠合NodeList对象,然后又在其他地方对这个元素举行操纵(增添,修正,删除子元素等操纵),这些变动将自动反射到NodeList中,不须要手动举行操纵。

由于getElementsByTagName(一切getElement…要领都邑返回动态NodeList)要领返回的是一个动态鸠合,所以只需document发生变化,就会自动更新对应的元素。因而,下面的代码是一个死轮回:

var divs = document.getElementsByTagName("div");
var i=0;
while(i < divs.length){
  document.body.appendChild(document.createElement("div"));
  i++;
}

死轮回的缘由是每次轮回都邑从新盘算divs.length.每次迭代都邑增添一个新的<div>,所以每次i++,对应的divs.length也在增添,所以i永久比divs.length小,轮回停止前提也就永久不会触发。

处置惩罚上述代码死轮回的方法能够是用一个变量存储divs.length或许改用querySelectorAll():

var divs = document.getElementsByTagName("div");
var i=0,len = divs.length;
while(i < len){
    document.body.appendChild(document.createElement("div"));
    i++;
}

你能够会以为这类动态鸠合是个坏主意, 但经由过程动态鸠合能够保证某些运用异常广泛的对象在种种情况下都是同一个,而且动态NodeList比静态NodeList快许多许多(下面诠释缘由)

静态NodeList

querySelectorAll()和querySelector()要领返回的是一个静态的NodeList,所谓静态NodeList就是对底层document的变动不会影响到返回的这个NodeList对象.此时返回的NodeList只是querySelectorAll()要领被挪用时的文档状况的快照。所以下面的代码不会是死轮回:

var divs = document.querySelectorAll("div");
var i=0;
while(i < divs.length){
    document.body.appendChild(document.createElement("div"));
    i++;
}

在这类情况下没有死轮回, divs.length的值永久不会转变, 所以只需不满足轮回前提, 就退出轮回。

为何动态NodeList更快呢?

我在某篇文章中看到有人测试了一下getElementsByTagName()比querySelectorAll()快好多倍。

缘由是:动态NodeList对象在浏览器中能够更快地被建立并返回,由于他们不须要预先猎取一切的信息,而静态NodeList对象从一最先就须要获得并封装一切相干的数据。两种对象范例的建立体式格局是完整差别的。

DynamicNodeList(动态NodeList)对象经由过程在cache缓存中注册它的存在并建立。从本质上讲,建立一个新的DynamicNodeList是异常轻量级的,由于不须要做任何的前期工作。每次接见 DynamicNodeList 时, 必需查询 document 的变化, length 属性 以及 item() 要领证明了这一点

比拟之下,StaticNodeList对象实例由别的一个文件建立,然后轮回添补一切的数据。在document中实行静态查询的前期本钱比拟DynamicNodeList要明显进步许多倍。

假如真正的检察WebKit的源码,你会发明他为 querySelectorAll() 明确地 建立一个返回对象 ,在个中又运用一个轮回来猎取每个效果,并建立终究返回的一个 NodeList.

结论

getElementsTagName()要领速率比querySelectorAll()要领快的根本缘由在于动态NodeList和静态NodeList对象差别。在猎取NodeList时不须要实行许多前期处置惩罚操纵的动态列表总比猎取返回之前完成种种处置惩罚的静态NodeList要快许多。哪一个要领更好用照样看你的需求。假如不须要猎取快照,就运用getElement…要领;假如须要静态快照效果,或许须要运用更庞杂的css查询,则能够斟酌querySelectAll()要领

对开首问题解说

/**经由过程querySelectorAll()猎取到的元素鸠合temp是静态的快照,所以temp长度不会变化,max一直为3,所以经由过程for轮回3个对应元素的class名字都被改成"new_class"**/
var temp = document.querySelectorAll(".class");
for (var i=0, max=temp.length; i<max; i++) { 
     temp[i].className = "new_class";
}
/**经由过程getElementsByClassName()猎取到的元素鸠合temp是动态的,所以我们对元素任何的变动都邑直接反应到对应的NodeList中;
刚最先temp长度为3,也就是max为3,这里i=0的时刻,变动了temp[0]的className为"new_class",所以temp的长度立时发生变化,max变成2;
继承轮回,i=1的时刻,temp[1]实际上是没变化前的temp[2]。此时又变动了temp[1]的className为"new_class",所以temp的长度又发生变化,max变成1;
继承轮回,i=2的时刻,不满足前提,轮回完毕;
所以temp[0],temp[2]的className都变成"new_class",而temp[1]没转变**/
var temp = document.getElementsByClassName("class");
for (var i=0, max=temp.length; i<max; i++) { 
     temp[i].className = "new_class";
} 

参考材料链接:

https://github.com/cncounter/…

    原文作者:Change
    原文地址: https://segmentfault.com/a/1190000008829267
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞