引言
在使用JavaSscrpi的NodeList时。本小白最初误以为这就是简单的Node型的数组,想要用它调用一些数组方法,但在运行过程中却出现了报错。如下所示
const ps=document.getElementsByTagName("p");
const p=document.createElement("p");
p.innerText="good";
ps.push(p);
报错提示:
*Uncaught TypeError: ps.push is not a function*
但在查阅相关资料后,才发现NodeList是JavaSrpit中的一个类似数组的对象(Like Array Object),是节点的集合对象,并非是数组。
NodeLisde的使用
为什么NodeList不是数组?
NodeList 对象在某些方面和数组非常相似,看上去可以直接使用从 Array.prototype 上继承的方法。然而,除了 forEach 方法,NodeList 没有这些类似数组的方法。
虽然NodeList不是数组,但是还是可以通过for循环进行遍历.
for (var i = 0; i < myNodeList.length; ++i) {
var item = myNodeList[i];
}
此外NodeList上也有一些其他方法
NodeList.item()
-
返回
NodeList对象中指定索引的节点,如果索引越界,则返回null。等价的写法是nodeList[i],不过,在这种情况下,越界访问将返回undefined。 -
NodeList.entries()返回一个迭代器,允许代码遍历集合中包含的所有键/值对。 (在这种情况下,键是从 0 开始的数字,值是节点。
-
NodeList.forEach()
每个 NodeList 元素执行一次提供的函数,将元素作为参数传递给函数。
-
NodeList.keys()返回一个迭代器,允许代码遍历集合中包含的键/值对的所有键。 (在这种情况下,键是从 0 开始的数字
-
NodeList.values()返回一个迭代器,允许代码遍历集合中包含的键/值对的所有值(节点)
NodeList是基于DOM的实时查询
NodeList对于DOM文档结构变化而言是“实时的”,文档结构的变化会实时的在它们身上反映出来,因此他们的值也始终代表文档的最新状态。废话少说上代码。
let divs=document.getElementsByTagName("div");
for(let i=0;i<divs.length;++i){
let div=document.createElement("div");
div.innerText="NodeList";
document.body.appendChild(div);
}
这个代码看上去没有问题,但实际上会导致无限循环。
第一行取得了包含文档中所有<div>元素的HTMLCollection.
因为这个集合是“实时的,所以任何时候只要向页面中添加一个新<div>元素,再查询这个集合就会多一项。因为浏览器不希望保存每次创建的集合,所以就会在每次访问时更新集合。
这样就会出现前面使用循环的例子中所演示的.每次循环开始,都会求值“i<divs.length” 这意味着要执行所有<div>元素的查询,因为循环体每次创建并向文档新增一个<div>,所以每次循环divs.length的值也会递增。因为两个值都会递增,所以i将永远不会等于divs.length.
那么怎么解决这个问题呢?
我们采用的方案是在迭代NodeList时,最好再初始化一个变量保存当时查询的长度,如下所示
let divs=document.getElementsByTagName("div");
for(let i=0,len=divs.length;i<len;++i){
let div=document.createElement("div");
div.innerText="NodeList";
document.body.appendChild(div);
}
一般来说,最好要限制操作NodeList的次数,因为每次操作都会搜索整个文档,所以最好吧NodeList存储起来
注意:
在有些情况下NodeList 是一个静态集合,也就意味着随后对文档对象模型的任何改动都不会影响集合的内容。比如 [document.querySelectorAll] 就会返回一个静态 NodeList。
最好牢记这种不同,尤其是在当你选择 NodeList 中所有项遍历的方式,或缓存它的长度的时候。