JavaScript高级程序设计之DOM之DOM 操作技术之使用NodeList第10.2.4讲

时间:2022-09-15 23:45:31
理解NodeList 及其“近亲”NamedNodeMap 和HTMLCollection,是从整体上透彻理解DOM 的
关键所在。这三个集合都是“动态的”;换句话说,每当文档结构发生变化时,它们都会得到更新。因
此,它们始终都会保存着最新、最准确的信息。从本质上说,所有NodeList 对象都是在访问DOM 文

档时实时运行的查询。例如,下列代码会导致无限循环:

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

第一行代码会取得文档中所有<div>元素的HTMLCollection。由于这个集合是“动态的”,因此
只要有新<div>元素被添加到页面中,这个元素也会被添加到该集合中。浏览器不会将创建的所有集
合都保存在一个列表中,而是在下一次访问集合时再更新集合。结果,在遇到上例中所示的循环代码
时,就会导致一个有趣的问题。每次循环都要对条件i < divs.length 求值,意味着会运行取得所
有<div>元素的查询。考虑到循环体每次都会创建一个新<div>元素并将其添加到文档中,因此
divs.length 的值在每次循环后都会递增。既然i 和divs.length 每次都会同时递增,结果它们的
值永远也不会相等。
如果想要迭代一个NodeList,最好是使用length 属性初始化第二个变量,然后将迭代器与该变
量进行比较,如下面的例子所示:

 

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

这个例子中初始化了第二个变量len。由于len 中保存着对divs.length 在循环开始时的一个快
照,因此就会避免上一个例子中出现的无限循环问题。在本章演示迭代NodeList 对象的例子中,使用
的都是这种更为保险的方式。
一般来说,应该尽量减少访问NodeList 的次数。因为每次访问NodeList,都会运行一次基于文
档的查询。所以,可以考虑将从NodeList 中取得的值缓存起来。

10.3
小结
DOM 是语言中立的API,用于访问和操作HTML 和XML 文档。DOM1 级将HTML 和XML 文档
形象地看作一个层次化的节点树,可以使用JavaScript 来操作这个节点树,进而改变底层文档的外观和
结构。
DOM 由各种节点构成,简要总结如下。
最基本的节点类型是Node,用于抽象地表示文档中一个独立的部分;所有其他类型都继承自
Node。
Document 类型表示整个文档,是一组分层节点的根节点。在JavaScript 中,document 对象是
Document 的一个实例。使用document 对象,有很多种方式可以查询和取得节点。
Element 节点表示文档中的所有HTML 或XML 元素,可以用来操作这些元素的内容和特性。
另外还有一些节点类型,分别表示文本内容、注释、文档类型、CDATA 区域和文档片段。

访问DOM 的操作在多数情况下都很直观,不过在处理<script>和<style>元素时还是存在一些
复杂性。由于这两个元素分别包含脚本和样式信息,因此浏览器通常会将它们与其他元素区别对待。这
些区别导致了在针对这些元素使用innerHTML 时,以及在创建新元素时的一些问题。
理解DOM 的关键,就是理解DOM 对性能的影响。DOM 操作往往是JavaScript 程序中开销最大的
部分,而因访问NodeList 导致的问题为最多。NodeList 对象都是“动态的”,这就意味着每次访问
NodeList 对象,都会运行一次查询。有鉴于此,最好的办法就是尽量减少DOM 操作。