js中的类数组对象---NodeList
动态 NodeList
这是⽂档对象模型(DOM,Document Object Model)中的⼀个⼤坑. NodeList对象(以及 HTML DOM 中的HTMLCollection对象)是⼀种特殊类型的对象. 对HTMLCollection对象的描述如下:
DOM中的NodeList和NamedNodeMap对象是动态的(live); 也就是说,对底层⽂档结构的修改会动态地反映到相关的集
合NodeList和NamedNodeMap中。例如, 如果先获取了某个元素(Element)的⼦元素的动态集合NodeList对象, 然后⼜在其他地⽅顺序添加更多⼦元素到这个DOM⽗元素中( 可以说添加, 修改, 删除⼦元素等操作), 这些更改将⾃动反射到NodeList, 不需要⼿动进⾏其他调⽤. 同样地, 对DOM 树上某个Node节点的修改,也会实时影响引⽤了该节点的NodeList和NamedNodeMap对象。
getElementsByTagName()⽅法返回对应标签名的元素的⼀个动态集合, 只要document发⽣变化,就会⾃动更新对应的元素。因此, 下⾯的代码实际上是⼀个死循环:
1// XXX 实际中请注意...
2// 适当的中间变量是⼀个好习惯
3var divs = ElementsByTagName("div");
4var i=0;
5
6while(i < divs.length){
7 document.body.ateElement("div"));
8 i++;
nodeselector9 }
死循环的原因是每次循环都会重新计算divs.length. 每次迭代都会添加⼀个新的<div>, 所以每次i++ ,对应的divs.length也在增加, 所以i永远
⽐divs.length⼩, 循环终⽌条件也就不会触发[例外情况是dom中没有div,不进⼊循环]。
你可能会觉得这种动态集合是个坏主意, 但通过动态集合可以保证某些使⽤⾮常普遍的对象在各种情况下都是同⼀个,
如document.images , document.forms, 以及其他类似的 pre-DOM集合。
静态 NodeList
querySelectorAll()⽅法的不同是它返回⼀个静态的NodeList. 这是表⽰的选择器API规范 :
querySelectorAll()⽅法返回的NodeList对象必须是静态的, ⽽不能是动态的([DOM-LEVEL-3-CORE], section 1.1.1). 后续对底层document的更改不能影响到返回的这个NodeList对象. 这意味着返回的对象将包含在创建列表那⼀刻匹配的所有元素节点。
所以即便是让querySelectorAll()和getElementsByTagName()具有相同的参数和⾏为, 他们也是有很⼤的不同点。在前⼀种情况下, 返回
的NodeList就是⽅法被调⽤时刻的⽂档状态的快照, ⽽后者总是会随时根据document的状态⽽更新。下⾯的代码就不会是死循环:
1var divs = document.querySelectorAll("div"),
2 i=0;
3
4while(i < divs.length){
5 document.body.ateElement("div"));
6 i++;
7 }
在这种情况下没有死循环, divs.length的值永远不会改变, 所以循环实际上就是将<div>元素的数量增加⼀倍, 然后就退出循环。
为什么动态 NodeList 更快呢?
动态NodeList对象在浏览器中可以更快地被创建并返回,因为他们不需要预先获取所有的信息, ⽽静态NodeList从⼀开始就需要取得并封装所有相关数据. 再三强调要彻底了解这⼀点, WebKit 的源码中对每种NodeList类型都有⼀个单独的源⽂件: 和 . 两种对象类型的创建⽅式是完全不同的。
DynamicNodeList对象通过在cache缓存中并创建。从本质上讲, 创建⼀个新的DynamicNodeList是⾮常轻量级的, 因为不需要做任何前期⼯作。每次访问DynamicNodeList时, 必须查询 document 的变化, length 属性以及 item() ⽅法证明了这⼀点(使⽤中括号的⽅式访问也是⼀样的).
相⽐之下, StaticNodeList对象实例由另⼀个⽂件创建,然后所有的数据。在 document 中执⾏静态查询的前期成本上⽐起DynamicNodeList要显著提⾼很多倍。
如果真正的查看WebKit的源码,你会发现他为querySelectorAll()明确地 ,在其中⼜使⽤⼀个循环来获取每⼀个结果,并创建最终返回的⼀
个NodeList.
结论
getElementsByTagName()速度⽐querySelectorAll()快的根本原因在于动态NodeList和静态NodeList对象的不同。尽管我可以肯定地说有某种⽅法来优化这⼀点, 在获取NodeList时不需要执⾏很多前期处理操作的动态列表,总⽐获取静态的集合(返回之前完成各种处理)要快很多。哪个⽅法更好⽤主要还是看你的需求, 如果只是要根据 tag name 来查元素, 也不需要获取此⼀个快照, 那就应该使⽤getElementsByTagName()⽅法; 如果需要快照结果(静态),或者需要使⽤复杂的CSS查询, 则可以考虑querySelectorAll()。
*以上内容来源于⽹络*
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论