我各位哥的友链:

大哥:emin.ink;二哥:ashtwo;三哥:pealipala.cn;

信息展示

昵称:aliveto 邮箱:some_body@foxmail.com

DOM中的NodeList对象与HTMLCollection对象

概述

旧样式集合(Old-style):NodeList 和 HTMLCollection。

集合(collection)是表示节点列表的对象。集合可以是实时或静态的。除非另有说明,集合必须是实时的(live)。

如果集合是实时的,那么该对象上的属性和方法必须对实际的底层数据操作,而不是数据的快照。

创建集合时,过滤器(filter)和根(root)将与其关联。

然后,集合表示根集于根集合的子树的视图,仅包含与给定过滤器匹配的节点。视图是线性的。在没有相反的特定要求的情况下,集合中的节点必须以树的顺序排序

NodeList

NodeList 对象是节点的集合

NodeList实例对象是一个类似数组的对象,它的成员是节点对象。Node.childNodes
document.querySelectorAll()返回的都是NodeList实例对象。NodeList 对象代表一个有序的节点列表

NodeList实例对象可能是动态集合,也可能是静态集合。所谓动态集合就是一个活的集合,DOM树删除或新增一个相关节点,都会立刻反映在NodeList接口之中。

有时,它是一个实时的集合,例如 Node.childNodes


<script>
    var parent = document.getElementById('parent');
    var child_nodes = parent.childNodes;
    console.log(child_nodes.length); // 我们得到了 "2"
    parent.appendChild(document.createElement('div'));
    console.log(child_nodes.length); // 此时输出 "3"
</script>

有时,它是一个静态的集合,document.querySelectorAll 所返回的节点就是静态的,也就是一个快照。也就意味着随后对 DOM 的任何改动都不会影响集合的内容。

NodeList对象有个length属性和item()方法,length表示所获得的NodeList对象的节点个数,这里还是要强调的是节点,而item()可以传入一个索引来访问Nodelist中相应索引的元素。

它是一个类数组对象


<body>
    <div id="node">
        文本节点
        <!-- 注释节点 -->
        <span>node1</span>
        <span>node2</span>
        <span>node3</span>
   </div>
</body>
<script>
    var node = document.getElementById('node'),
        nodeLists = node.childNodes
    console.log(nodeLists.length) //     输出为9
    console.log(nodeLists) //    NodeList[text, comment, text, span, text, span, text, span, text]
    console.log(document.querySelectAll('span')) //    NodeList[span,span,span,span]
</script>

上面的HTML代码中,文本节点”和父节点子节点的空格(连着的文本)算做一个文本节点,然后是一个注释节点和注释节点和元素节点之间的空格(换行会产生空格,空格算做文本节点)的文本节点,紧接着的是一个元素节点和元素节点之间的换行的文本节点,三个元素节点和元素节点间的两个文本节点,最后是最后得元素节点和父元素之间的空格产生的文本节点,总共是9个节点。

NodeList对象的一大特点是它返回的内容是动态的(live),也就是说我们上面代码获取nodeLists是类似于“指针”的东西,所以在下面代码中我们在获取了nodeLists之后再向node中插入一个创建的span标签后,发现获取到了nodeLists.length变为10了,但是querySelectorAll这个接口返回的nodeList对象比较特殊,它是个静态(static)的对象。而且是指定元素的节点集合(返回结果如下面代码 所示)


<body>
    <div id="node">
        文本节点
        <!-- 注释节点 -->
        <span>node1&alt/span>
        <span>node2</span>
        <span>node3</span>
   </div>
</body>
<script>
     var node = document.getElementById('node')
     var nodeLists = node.childNodes
     var queryNodes = node.querySelectorAll('span')
     node.appendChild(document.createElement('span'))
    console.log(nodeLists.length)  // 输出为10
    console.log(queryNodes.length)  //输出为3

    console.log(nodeLists) //    NodeList[text, comment, text, span, text, span, text, span, text]
    console.log(document.querySelectAll('span')) //    NodeList[span,span,span,span]
</script>

HTMLCollection

HTMLCollection 对象是元素的集合。

它和NodeList很像,有length属性来表示HTMLCollection对象的长度,也可以通过elements.item()传入元素索引来访问。当时它还有一个nameItem()方法,可以返回集合中name属性和id属性值得元素。HTMLDocument 接口的许多属性都是 HTMLCollection 对象,它提供了访问诸如表单、图像和链接等文档元素的便捷方式,比如document.images和document.forms的属性都是HTMLCollection对象。

它们之间的区别:NodeList 返回的是各节点;而 HTMLCollection 返回的是元素节点。

它们间的共同点:HTMLCollection的集合和NodeList对象一样也是动态的,他们获取的都是节点或元素集合的一个引用

官方文档中有下列这句话,需要我们谨慎对待它:

HTMLCollection 是一个历史的工件,我们不能从 web 中摆脱它。虽然开发人员当然欢迎继续使用它,但新的 API 标准设计者不应该使用它。

HTMLCollection和NodeList 实时性

HTMLCollection和NodeList的实时性非常有用,但是,我们有时要迭代一个NodeList或HTMLCollection对象的时候,我们通常会选择生成当前对象的一个快照或静态副本:这样的话,我们就可以放心的对当前的DOM集合做一些删减和插入操作,这个在DOM密集操作的时候很有用。

还有MDN上面提到了一个将NodeList转化为Array的DOM扩展原型的方法(在ie6/7中存在危险)

总结:

至于这两个集合之间的关联,那是历史问题了,这里就不再做深究了。你只需要知道 NodeList 最初设计是给 XML 使用的,为了解析XML,后来延用到html上。而 DOM 中就会返回元素节点和文本节点,通常就产生了我们不想要的东西,比如 IE6 ~ 8 会返回我们的注释,也将它们作为了节点;因此,后来也就诞生了 HTMLCollection,它就只返回元素节点,这通常是我们想要的。例如 getElements* 系列:getElementsByTagName,getElementsByClassName,getElementsByName 等等。
额外的补充:我们可以把DOM分为两部分 core 和 html,Core 部分提供最基础的 XML 解析API说明,HTML 部分专为 HTML 中的 DOM 解析添加其特有的 API。NodeList接口是在core中体现的,HTMLCollection则是在html部分,不同浏览器也会实现它们的不同接口,厂商联盟性质的规范组织出现会让这些更加规范,也不出现之前返回的是NodeList对象,但是却是静态的。