⛱️序言
犹记得上回有一次面试的时候被问到 htmlCollection
和数组的关系。当时的我心里想的是, html
中的集合和数组的关系,那解题就是说 set
和数组的关系?
于是……面试官当下立即纠正我, htmlCollection
是单词连在一起的,是 js
的一个内容。当时我可能是想……找个地洞钻……
不会的咋还是得虚心接收,查漏补缺还是比较合理。经过一系列的资料查询和总结之后,得出以下总结。
下面开始进入本文的讲解~🙋
🎈一、基础知识
1. 定义
(1)HTMLCollection
HTMLCollection
表示一个包含了元素(元素顺序为文档流中的接口)的集合(通用集合),还提供了从该集合中选择元素的属性和方法。- 例如使用
getElementsByTagName()
方法返回的就是一个HTMLCollection
对象。
(2)NodeList
NodeList
对象是节点的集合。- 通过以下方法,可以获取到
NodeList
对象。主要有:①在一些旧版本浏览器中的方法,比如getElementsClassName()
方法,返回的是NodeList
对象,而不是HTMLCollection
对象。②所有浏览器的Node.childNodes
属性返回的都是NodeList
对象。③大部分浏览器的document.querySelectorAll()
返回的是NodeList
对象。 - 我们可以通过以下代码进行验证:
document.body.childNodes instanceof NodeList // true document.querySelector('body') instanceof NodeList // true or false document.getElementByClassName('body') instanceof NodeList // true or false 复制代码
2. 属性和方法
(1)HTMLCollection
HTMLCollection
对象中的属性和方法,举例两个:
item(index)
—— 返回HTMLCollection
中指定索引的元素,如果不存在则返回null
;length
(只读) —— 返回HTMLCollection
中元素的数量。
接下来用一个例子来进行阐述验证。具体代码如下:
document.getElementsByTagName('body') instanceof HTMLCollection // true const htmlCollection = document.getElementsByTagName('body') console.log(htmlCollection.item(0)) // <body>...</body> console.log(htmlCollection.length()) // 1 复制代码
(2)NodeList
NodeList
对象中的属性和方法主要有以下几种。包括:
item()
—— 返回某个元素基于文档数的索引;length()
—— 返回NodeList
中的节点数量;NodeList.forEach()
—— 该方法用于遍历NodeList
中的所有成员。它接收一个回调函数作为参数,每遍历一回就要执行这个回调函数一次,用法与数组实例的forEach
方法是完全一致的;NodeList.keys()/values()/entries()
—— 对于这三个方法来说,它们都会返回一个ES6
的遍历器对象,可以通过for…of…
来进行循环遍历,以便于获取每一个成员的信息。
同时,需要注意以上三者的区别,分别如下:
- keys() —— 指的是返回键名的遍历器;
- values() —— 指的是返回键值的遍历器;
- entries() —— 指的是返回的遍历器要同时包含键名和键值的信息。
我们写点代码来论证以上内容。具体代码如下:
const nodelist = document.querySelectorAll('body') console.log(nodelist.item(0)) // <body>...</body> console.log(nodelist.length) // 1 console.log(nodelist.forEach(item => console.log(item))) // <body>...</body> for(var key of nodelist.keys()) { console.log(nodelist[key]) // <body>...</body> } for(var value of nodelist.values()) { console.log(value) // <body>...</body> } for(var entry of nodelist.entries()) { console.log(entry) // [0, body] } 复制代码
🪁二、异同点
1. HTMLCollection 与 NodeList 的区别
HTMLCollection | NodeList | |
集合 | 元素的集合 | 节点的集合 |
静态和动态 | HTMLCollection 是动态绑定的,是一个动态集合。DOM 树发生变化,HTMLCollection 也会随之变化,说明其节点的增删是敏感的 | NodeList 是一个静态集合,其不受 DOM 树元素变化的影响;相当于是 DOM 树、节点数量和类型的快照,也就是说对节点进行增删操作时,NodeList 是感觉不到的。但是对节点内部内容修改,是可以感觉得到的,比如修改 innerHTML |
节点 | 不包含属性节点和文本节点 | 只有 NodeList 对象有包含属性节点和文本节点 |
元素获取方式 | HTMLCollection 元素可以通过 name,id 或 index 索引来获取 | NodeList 只能通过 index 索引来获取 |
伪数组 | HTMLCollection 和 NodeList 都是类数组,不是数组,只是长得像数组而已。所以无法使用数组的方法,比如: pop(),push(),或 join() 等等 | 与 HTMLCollection 一样 |
2. querySelectorAll 和 getElementsByTagName 的区别
在上述的表格中我们可以了解到, HTMLCollection
是动态集合,当 DOM
树发生变化时, HTMLCollection
也会随之改变。而 NodeList
是静态集合,当 DOM
树发生变化时, NodeList
不会受到 DOM
树变化的影响。我们来举两个例子进行阐述说明。
(1)querySelectorAll
先附上代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>htmlCollection和NodeList</title> </head> <body> <ul> <li></li> <li></li> <li>MondayLab</li> <li></li> <li></li> </ul> <script> var oldUl = document.querySelectorAll('ul')[0]; var oldLi = document.querySelectorAll('li'); console.log(oldUl); // NodeList[body] console.log(oldLi.length); // 5 var newLi = document.createElement('li'); oldUl.appendChild(newLi); console.log(oldLi.length); // 5 var length = oldLi.length - 1; oldLi[length].innerHTML = 'monday'; console.log(oldLi[length].innerHTML); // monday console.log(oldLi.length); // 5 → 虽然通过innerHTML可以读到文本节点的内容,但是长度依旧不变,还是5 </script> </body> </html> 复制代码
大家可以看到,使用 querySelectorAll
来获取 <li>
,返回的是一个 NodeList
的集合。且当页面 DOM
结构发生改变时,其长度不会发生任何的改变。但是当改变 innerHTML
时,则文本节点的内容会发生改变。值得注意的是,即使 innerHTML
改变 DOM
的结构,但长度依旧是不变的,还是 5
。
(2)getElementsByTagName
先附上代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>HTMLCollection</title> </head> <body> <ul> <li></li> <li></li> <li>MondayLab</li> <li></li> <li></li> </ul> <script> var oldUl = document.getElementsByTagName('ul')[0]; var oldLi = document.getElementsByTagName('li'); console.log(oldUl); // HTMLCollection[body] console.log(oldLi.length); // 5 var newLi = document.createElement('li'); oldUl.appendChild(newLi); console.log(oldLi.length); // 6 → 顺利改变 DOM 的结构 </script> </body> </html> 复制代码
大家可以看到,使用 getElementByTagName
时,获取的是一个 HTMLCollection
集合,这个时候说明对节点进行增删操作时,页面的 DOM
结构会发生改变,且HTMLCollection
将实时地获取到集合的长度。
📞三、结束语
写到这里的时候,不得不感概 js
的 DOM
操作是如此的强大,也突然就明白了自己之前写代码的时候为啥会遇到那么多坑。如果在学习之初就追溯于原理,可能跳的坑应该就能少很多了。
讲到这里,关于 HTMLCollection
和 NodeList
的内容就结束啦!希望对大家有帮助~
彩蛋有几篇我看过还比较好理解的文章,有需要可以当扩展知识进行扩充哦~