概念和区别
NodeList 对象是节点的集合,通常是由属性,如Node.childNodes 和 方法,如document.querySelectorAll 返回的。
备注: NodeList 不是一个数组,是一个类似数组的对象 (Like Array Object)。虽然 NodeList 不是一个数组,但是可以使用 forEach() 来迭代。
HTMLCollection 接口表示一个包含了元素(元素顺序为文档流中的顺序)的通用集合(与 arguments 相似的类数组 (array-like) 对象),还提供了用来从该集合中选择元素的方法和属性。备注: HTML DOM 中的 HTMLCollection 是即时更新的(live);当其所包含的文档结构发生改变时,它会自动更新。因此,最好是创建副本(例如,使用 Array.from)后再迭代这个数组以添加、移动或删除 DOM 节点。
两者的属性和方法,如下图:
具体用法
个人理解:
NodeList:只有querySelectorAll返回的是NodeList,这不是数组而是类数组,适用for循环和forEach方法,而适用forEach就一定会适用for in和 for of。
HTMLCollection:除了querySelectorAll返回的是NodeList,其余都是HTMLCollection,与NodeList接口不同的是:HTMLCollection没有forEach方法,只能使用for循环遍历。
例子:
<!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>Document</title>
</head>
<div id="box">
<div class="a">aaa</div>
<div class="a">bbb</div>
</div>
<script>
// 1. HTMLCollection形式
let element1 = document.getElementsByClassName(
'a'
);
console.log(element1); // HTMLCollection
// 报错
// element1.forEach(function (ele) {
// console.log(ele);
// });
// 优化1
[].forEach.call(element1, function (el) {
console.log(el, '优化1');
});
// 优化2
Array.from(element1).forEach(function (el) {
console.log(el, '优化2');
})
// 优化3
for (let index = 0; index < element1.length; index++) {
// const element = array[index];
console.log(element1[index], '优化3');
}
// 2. NodeList形式
let element2 = document.querySelectorAll('.a')
console.log(element2); // NodeList
// 方法1,不报错
element2.forEach(function (ele) {
console.log(ele);
});
// 方法2
for (const ele of element2) {
console.log(ele);
}
// 方法3
for (let index = 0; index < element2.length; index++) {
// const element = array[index];
console.log(element2[index], '方法3');
}
// ...
</script>
<style>
#a {
width: 10vw;
height: 10vh;
background-color: antiquewhite;
}
</style>
</html>
// 报错
element1.forEach(element => {
console.log(element);
});
// 不报错
[].forEach.call(element1, function (el) {
console.log(el, '优化1');
});
个人理解:element1是一种无法用forEach的类数组(并不是类数组就无法forEach,比如:Nodelist)。不报错的写法中,调用空数组的 forEach 方法,第1个参数:element1是把[]的this指向指给element1,第2个参数:是把函数当成参数传入forEach的回调函数中
产生的联想
-
nextElementSibling 和 nextSibling的区别 -
Children 和 Childnodes的区别 -
parentNode 和 parentElement的区别 -
....
元素节点(HTMLCollection):nextElementSibling 和 Children适用,(包括文本节点、注释节点即回车、换行、空格、文本等等)
节点(Nodelist):nextSibling 和 Childnodes适用,(不包括文本节点、注释节点等等)
Tips:由上图可以看出,HTMLCollection是Nodelist集合的一种。
例子: js节点问题:交换两个节点
<!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>Document</title>
</head>
<div class="box">
<div id="a">aaa</div>
<div id="b">bbb</div>
</div>
<script>
var a = document.getElementById("a");
var b = document.getElementById("b");
const swap = function (nodeA, nodeB) {
const parentA = nodeA.parentNode;
console.log(nodeB.nextElementSibling); // 理解了nextSibling,就可以用nextElementSibling来简化了
if (nodeB.nextElementSibling === nodeA) {
parentA.insertBefore(nodeA, nodeB);
} else {
parentA.insertBefore(nodeB, nodeA);
}
};
swap(a, b)
</script>
</html>