DOM是JavaScript中重要部分之一,在DOM中有一个动态集合。
这个动态集合包含节点的集合(NodeList)、元素属性的集合(NamedNodeMap)和HTML元素的集合(HTMLCollection)。这三个对象都是类数组(Array-like),具有像数组一样的特性
类数组:比如arguments
- 具有:指向对象元素的数字索引下标以及length属性告诉我们对象的元素个数
- 不具有:不具有诸如push()、forEach()以及indexOf()等数组对象具有的方法
将类数组对象转换为数组
//es5
let arr = Array.prototype.slice.call(arguments);
//es6
let arr = Array.from(arguments);
//还可以使用ES6中的扩展运算符...将某些数据结构转换成数组,这种数据结构必须有遍历器接口。
let arr = [...arguments];
NodeList集合
- NodeList实例是一个类似数组的对象,它的成员是节点对象。通过以下方法可以得到NodeList实例。
Node.childNodes
document.querySelectorAll()、
HTMLCollection
- 一个节点对象的集合,只能包含元素节点(element),不能包含其他类型的节点。
- HTMLCollection的集合可以通过getElementsByTagName()、getElementsByName()、document.getElementsByClassName()、document.anchors、document.forms、document.images和documnet.links等方式来获取。
NameNodeMap集合
DOM中的Element节点是唯一拥有attributes属性的一种节点类型。而attributes属性中就包含NamedNodeMap集合。NamedNodeMap集合的元素拥有nodeName和nodeValue属性,分别表示元素节点名称和值。
三者的异同
共同点
-
三者都具有length属性
-
三者都有item()方法
-
三者都是动态的,如果对NodeList和HTMLCollection中的元素进行操作都会直接反映到DOM中,因此如果一次性直接在集合中进行DOM操作,开销非常大
不同之处:
-
NodeList里面包含了所有的节点类型
-
HTMLCollection里面只包含元素节点
-
NamedNodeMap里面包含了Attribute的集合,例如id、title、class等,集合中的每一个元素都是attr类型
-
三者所提供的方法也有不同,例如HTMLCollection中提供了namedItem(),而NodeList和NamedNodeMap两个集合中没有namedItem()方法
动态NodeList和静态NodeList
- getElementsByTagName()方法返回一个动态(live)的HTMLCollection,
- 而querySelectorAll()返回的是一个静态(static)的NodeList
动态集合
DOM中的NodeList和NamedNodeMap对象是动态的;也就是说,对底层文档结构的修改会动态地反映到相关的集合NodeList和NamedNodeMap中。例如,如果先获取了某个元素(Element)的子元素的动态集合NodeList对象,然后又在其他地方顺序添加更多子元素到这个DOM父元素中(可以说添加、修改、删除子元素等操作),这些更改将自动反射到NodeList,不需要手动进行其他调用。同样地,对DOM树上某个Node节点的修改,也会实时影响引用了该节点的NodeList和NamedNodeMap对象。
静态集合
querySelectorAll()方法返回的NodeList对象必须是静态的,而不能是动态的。后续对底层document的更改不能影响到返回的这个NodeList对象。这意味着返回的对象将包含在创建列表那一刻匹配的所有元素节点
<html>
<head>
<title>DOM Tree</title>
</head>
<body>
<div id="box">
<div>Title</div>
<div class="item">Item1</div>
<div class="item">Item2</div>
<div class="item">Item3</div>
<div class="item">Item4</div>
<div class="item">Item5</div>
</div>
</body>
</html>
let box = document.getElementById('box')
let liveNodeList1 = document.getElementsByTagName('div')
console.log(liveNodeList1)
let liveNodeList2 = document.getElementsByClassName('.item')
console.log(liveNodeList2)
let liveNodeList3 = document.querySelectorAll('.item')
console.log(liveNodeList3)
let children = box.childNodes;
console.log(children, children.length)
1..png
为什么动态集合比静态集合更快
为什么说getElementsByTagName()在所有浏览器上都比auerySelectorAll()要快好多倍。
- 让 querySelectorAll() 和 getElementsByTagName() 具有相同的参数和行为, 但有很大的不同点。 在前一种情况下, 返回的 NodeList 就是方法被调用时刻的文档状态的快照, 而后者总是会随时根据document的状态而更新
- 使用getElementsByTagName()方法我们得到的结果就像是一个对象的索引,而通过querySelectorAll()方法我们得到的是一个对象的克隆;所以当这个对象数据量非常大的时候,显然克隆这个对象所需要花费的时间是很长的
let box = document.getElementById('box')
let liveNodeList = document.getElementsByTagName('div')
console.log(liveNodeList, liveNodeList.length)
let newEle = document.createElement('div')
newEle.textContent = '新创建的div元素'
box.appendChild(newEle)
console.log(liveNodeList, liveNodeList.length)
2.png
let box = document.getElementById('box')
let liveNodeList = document.querySelectorAll('div')
console.log(liveNodeList, liveNodeList.length)
let newEle = document.createElement('div')
newEle.textContent = '新创建的div元素'
box.appendChild(newEle)
console.log(liveNodeList, liveNodeList.length)
liveNodeList = document.querySelectorAll('div')
console.log(liveNodeList, liveNodeList.length)
3.png
网友评论