js中的类数组对象---NodeList
动态 NodeList
这是文档对象模型(DOM,Document Object Model)中的一个大坑. NodeList 对象(以及 HTML DOM 中的 HTMLCollection对象)是一种特殊类型的对象. DOM Level 3 spec 规范 对 HTMLCollection 对象的描述如下:
DOM中的 NodeList 和 NamedNodeMap 对象是动态的(live); 也就是说,对底层文档结构的修改会动态地反映到相关的集合NodeList 和 NamedNodeMap 中。 例如, 如果先获取了某个元素(Element)的子元素的动态集合 NodeList 对象, 然后又在其他地方顺序添加更多子元素到这个DOM父元素中( 可以说添加, 修改, 删除子元素等操作), 这些更改将自动反射到NodeList, 不需要手动进行其他调用. 同样地, 对DOM树上某个Node节点的修改,也会实时影响引用了该节点的 NodeList和 NamedNodeMap 对象。
getElementsByTagName() 方法返回对应标签名的元素的一个动态集合, 只要document发生变化,就会自动更新对应的元素。 因此, 下面的代码实际上是一个死循环:
// XXX 实际中请注意...
// 适当的中间变量是一个好习惯
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小, 循环终止条件也就不会触发[例外情况是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的状态而更新。 下面的代码就不会是死循环:
var divs = document.querySelectorAll("div"),
i=0;
while(i < divs.length){
document.body.appendChild(document.createElement("div"));
i++;
}
在这种情况下没有死循环, divs.length的值永远不会改变, 所以循环实际上就是将 <div> 元素的数量增加一倍, 然后就退出循环。
为什么动态 NodeList 更快呢?
动态 NodeList 对象在浏览器中可以更快地被创建并返回,因为他们不需要预先获取所有的信息, 而静态 NodeList 从一开始就需要取得并封装所有相关数据. 再三强调要彻底了解这一点, WebKit 的源码中对每种 NodeList 类型都有一个单独的源文件: DynamicNodeList.cpp 和 StaticNodeList.cpp. 两种对象类型的创建方式是完全不同的。
DynamicNodeList 对象通过在cache缓存中 注册它的存在 并创建。 从本质上讲, 创建一个新的 DynamicNodeList 是非常轻量级的, 因为不需要做任何前期工作。 每次访问 DynamicNodeList 时, 必须查询 document 的变化, length 属性 以及 item() 方法证明了这一点(使用中括号的方式访问也是一样的).
相比之下, StaticNodeList 对象实例由另一个文件创建,然后循环填充所有的数据 。 在 document 中执行静态查询的前期成本上比起 DynamicNodeList 要显著提高很多倍。
如果真正的查看WebKit的源码,你会发现他为 querySelectorAll() 明确地 创建一个返回对象 ,在其中又使用一个循环来获取每一个结果,并创建最终返回的一个 NodeList.
结论
getElementsByTagName() 速度比 querySelectorAll() 快的根本原因在于动态NodeList和静态NodeList对象的不同。 尽管我可以肯定地说有某种方法来优化这一点, 在获取NodeList时不需要执行很多前期处理操作的动态列表,总比获取静态的集合(返回之前完成各种处理)要快很多。 哪个方法更好用主要还是看你的需求, 如果只是要根据 tag name 来查找元素, 也不需要获取此一个快照, 那就应该使用 getElementsByTagName()方法; 如果需要快照结果(静态),或者需要使用复杂的CSS查询, 则可以考虑 querySelectorAll()。
*以上内容来源于网络*
js中的类数组对象---NodeList的更多相关文章
- 浅谈JavaScript和DOM中的类数组对象
JavaScript是一门弱类型语言,它的数据类型分为两大类:简单数据类型(5种:Undefined.Null.Boolean.Number.String)和复杂数据类型(1种:Object).Obj ...
- JavaScript中的类数组对象
在javascript中,对象与数组都是这门语言的原生规范中的基本数据类型,处于并列的位置. 一般来说,如果我们有一个对象obj和一个数组a: obj["attr1"]; / ...
- js中的类和对象以及自定义对象
js中的类 1.类的声明 function Person(name,age){ this.name=name; this.age=age; this.test=function(a){ alert(a ...
- (一)类数组对象NodeList
NodeList对象的特点: NodeList是一种类数组对象,用于保存一组有序的节点. 可以通过方括号语法来访问NodeList的值,有item方法与length属性. 它并不是Array的实例,没 ...
- js中有关类、对象的增强函数
javascript中继承的实现 基础实现 function Range(from,to){ this.from =from; this.to =to; } Range.prototype = { i ...
- js中对类和对象的理解
类 :对一群具有相同特征的对象的集合的描述:对象:真实存在的对象个体: **面向对象,而不是面向类. 1.一切皆对象,继承靠原型链,多态靠弱类型,封装--虽然可以靠闭包,但我个人更推崇和python一 ...
- [JS]如何理解JS中的类和对象
-------------------------------------------------------------------------------------------- 变量:自由的 ...
- JS中集合对象(Array、Map、Set)及类数组对象的使用与对比
原文地址 在使用js编程的时候,常常会用到集合对象,集合对象其实是一种泛型,在js中没有明确的规定其内元素的类型,但在强类型语言譬如Java中泛型强制要求指定类型. ES6引入了iterable类型, ...
- 简述JavaScript对象、数组对象与类数组对象
问题引出 在上图给出的文档中,用JavaScript获取那个a标签,要用什么办法呢?相信第一反应一定是使用document.getElementsByTagName('a')[0]来获取.同样的,在使 ...
随机推荐
- ubuntu ulimit 设置
永久设置ubuntu ulimit 之前是ulimit -n 65535那样设置,不过貌似只是当前环境有效果,重启服务器的话,又失效了...今天无意找到一个设置的方法,可以永久设置ulimit的参数. ...
- 自定义带动画的Toast
一.style样式: 1. // 移动和透明渐变结合的动画 <style name="anim_view"> <item name="@ ...
- WPF 调用WinForm控件
WPF可以使用WindowsFormsHost控件做为容器去显示WinForm控件,类似的用法网上到处都是,就是拖一个WindowsFormsHost控件winHost1到WPF页面上,让后设置win ...
- eclipse 导入工程报错Unable to execute dex: Multiple dex files define Landroid/annotation/SuppressLint
对策: 检查libs 是否有重复加载的.
- php session的操作
[设置session数据] <?php session_start(); //初始化 //session文件中可以保存 dobule,integer,bool,array,object $_SE ...
- DateTimePicker如何与Delphi自带Style同步
Delphi 的 DateTimePicker 组件有一个CalColors属性,可以设置 DropDown 打开的日历节目的风格.但如果不使用 Delphi 自带的 Style,在这里设置属性看不到 ...
- C++程序内存泄漏检测方法
一.前言 在Linux平台上有valgrind可以非常方便的帮助我们定位内存泄漏,因为Linux在开发领域的使用场景大多是跑服务器,再加上它的开源属性,相对而言,处理问题容易形成“统一”的标准.而在W ...
- CMT learning
一个 GMT 命令由"gmt + 模块 + 选项 + 参数"构成,写成如下形式: gmt module -Axx+bxxxx -Bxx+axxxx • gmt 是 GMT 中&qu ...
- EL和JSTL专题
EL简介 EL全名为Expression Language,它原本是JSTL 1.0为方便存取数据所自定义的语言.当时只能在JSTL标签中使用,如下: <c:out value="${ ...
- SSH面试题收藏
Hibernate工作原理及为什么要用? 原理: 1. 读取并解析配置文件2. 读取并解析映射信息,创建SessionFactory3. 打开Sesssion4. 创建事务Transation5. 持 ...