动态 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的更多相关文章

  1. 浅谈JavaScript和DOM中的类数组对象

    JavaScript是一门弱类型语言,它的数据类型分为两大类:简单数据类型(5种:Undefined.Null.Boolean.Number.String)和复杂数据类型(1种:Object).Obj ...

  2. JavaScript中的类数组对象

    在javascript中,对象与数组都是这门语言的原生规范中的基本数据类型,处于并列的位置. 一般来说,如果我们有一个对象obj和一个数组a: obj["attr1"];    / ...

  3. js中的类和对象以及自定义对象

    js中的类 1.类的声明 function Person(name,age){ this.name=name; this.age=age; this.test=function(a){ alert(a ...

  4. (一)类数组对象NodeList

    NodeList对象的特点: NodeList是一种类数组对象,用于保存一组有序的节点. 可以通过方括号语法来访问NodeList的值,有item方法与length属性. 它并不是Array的实例,没 ...

  5. js中有关类、对象的增强函数

    javascript中继承的实现 基础实现 function Range(from,to){ this.from =from; this.to =to; } Range.prototype = { i ...

  6. js中对类和对象的理解

    类 :对一群具有相同特征的对象的集合的描述:对象:真实存在的对象个体: **面向对象,而不是面向类. 1.一切皆对象,继承靠原型链,多态靠弱类型,封装--虽然可以靠闭包,但我个人更推崇和python一 ...

  7. [JS]如何理解JS中的类和对象

    -------------------------------------------------------------------------------------------- 变量:自由的 ...

  8. JS中集合对象(Array、Map、Set)及类数组对象的使用与对比

    原文地址 在使用js编程的时候,常常会用到集合对象,集合对象其实是一种泛型,在js中没有明确的规定其内元素的类型,但在强类型语言譬如Java中泛型强制要求指定类型. ES6引入了iterable类型, ...

  9. 简述JavaScript对象、数组对象与类数组对象

    问题引出 在上图给出的文档中,用JavaScript获取那个a标签,要用什么办法呢?相信第一反应一定是使用document.getElementsByTagName('a')[0]来获取.同样的,在使 ...

随机推荐

  1. “iTunes无法连接iPad,因为设备超时”解决办法

    注意一般要两个授权才会连接成功,一是在电脑上的iTunes登陆apple账户,账户授权电脑:二是ipad上信任Trust电脑连接ipad,如果没有重启iPad试试. 法1. 更新iTunes,重启电脑 ...

  2. win8.1安装Matlab7.0的兼容问题

     Matlab7.0安装完成后打开就立即关闭,此时右键点击MATLAB7.0快捷方式-"用图形处理器运行"-"更改默认图形处理器",将"集成图形&qu ...

  3. Android中的多线程编程

    问题 Android的UI也是线程不安全的,如果要更新应用程序里的UI元素,必须在主线程中进行,否则就会抛异常.比如用一个Button的onClick函数去更新界面上的元素,就会得到一个CalledF ...

  4. Android 设置ListView当前显示的item

    项目中可能会有这种需求:动态设置ListView显示的item 这种需求可能会出现在不同的情况下,有的是打开页面就要显示在特定的位置,也有的是浏览列表时实时更新数据并且改变了集合中数据,或者是某种条件 ...

  5. Redis概述

    1.       Redis是使用内存存储(in-momory)的非关系型数据. 2.       Redis的数据存储选项共有5种:字符串.列表.集合.散列表.有序集合. 3.       Redi ...

  6. mySql 基本语法学习笔记

     create database if not exists yang;    drop database if exists yang;     show databases;   show dat ...

  7. android 保存Bitmap 到本地 哦

    public String saveImage(Bitmap bmp) { File appDir = new File(Environment.getExternalStorageDirectory ...

  8. [小菜随笔]新手使用appium+python进行自动化测试过程中webdriver.Remote报错的错误分析方法(带实例)

    很多人刚开始使用python+appium去执行APP自动化的时候经常会遇到webdriver.Remote,报错位置指向都是driver = webdriver.Remote('http://127 ...

  9. Javascript DOM编程艺术 语法部分

    1.变量,可以变化的东西我们称为变量,随着年龄的增大,我们的age不断变大 2.Javascript变量声明用var,可以不声明变量类型.尽量声明为一个字符串字面量. 3.弱类型:要求程序员必须明确的 ...

  10. eap-peap/mschapv2

    eap-peap/mschapv2       文件路径 用途 示例 备注 #gedit /usr/local/etc/raddb/sites-available/default #gedit /us ...