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]来获取.同样的,在使 ...
随机推荐
- html5之canvas画图基础
HTML5+CSS3的好处是,你可以编写一个页面分别用于不同的平台,只需要设置不同的css样式就可以了,现在基本主流浏览器都支持全新的HTML5和CSS3,因为它的跨平台开发.因为是原生代码所以它的页 ...
- 《数据结构》2.2顺序表(sequence list)
//顺序表节点的定义 typedef struct { datatype data[MAXSIZE]; //数组容量的上限 int len; //记录最后一个元素的位置,相当于一个指针,表空时len= ...
- UML 类图常用表示方法.
UML中类图实例 接口:空心圆+直线(唐老鸭类实现了‘讲人话’): 依赖:虚线+箭头(动物和空气的关系): 关联:实线+箭头(企鹅需要知道气候才迁移): 聚合:空心四边形+实线+箭头(雁群和大雁的关系 ...
- 点击document隐藏某个div
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 一个简单的游戏开发框架(四.舞台Stage)
首先是StageManager类: class StageManager : public Singleton<StageManager> { friend class Singleton ...
- Sqrtx
我只能想出二分的方法,而且还不一定能写出最简洁的代码.无论刷多少遍,牛顿迭代法我都想不到,莫名有种悲哀的感觉:智力是硬伤啊.就算如此,却还要一遍遍不厌其烦地刷,这才是最悲剧的.多说无益,上代码. 二分 ...
- Linux学习 :移植linux-4.7.4到JZ2440开发板
一.编译环境搭建: 1.linux源码下载:https://www.kernel.org/2.安装交叉编译工具链: ①手动下载配置工具链: (1):解压 arm-linux-gcc-3.4.1.tar ...
- memset函数详解
语言中memset函数详解(2011-11-16 21:11:02)转载▼标签: 杂谈 分类: 工具相关 功 能: 将s所指向的某一块内存中的每个字节的内容全部设置为ch指定的ASCII值, 块的大 ...
- 【转】tomcat性能调优
一.总结前一天的学习 从"第三天"的性能测试一节中,我们得知了决定性能测试的几个重要指标,它们是: ü 吞吐量 ü Responsetime ü Cpuload ü ...
- Ubuntu下mysql-server的安装
(1)更新 #apt-get update (2)安装 #apt-get install mysql-server 出现窗口设置"root"用户的密码为"456456&q ...