初学JS时遇到某个节点的childNodes总是被告知:“就把它当做数组就可以了,其它的暂不用考虑”。可是,学习了一段时间之后,还是不免去想他们之间的关系,一个节点的childNodes到底是不是数组呢?
其实每个节点都有一个childNodes属性,其中保存着一个NodeList对象。NodeList是一种类数组对象,用于保存一组有序的节点。可是,虽然可以通过方括号索引来访问NodeList的值,而且这个对象也有length属性,但它并不是Array的实例。另外,NodeList还有一个item(idx)方法,返回NodeList对象中指定索引的节点,如果索引越界,则返回null。等价的写法是nodeList[idx],不过这种情况下越界访问将返回undefined。
大多数情况下,NodeList 对象都是个实时集合。意思是说,如果文档中的节点树发生变化,则已经存在的 NodeList 对象也可能会变化。例如,Node.childNodes 是实时的:
var parent = document.getElementById('parent');
var children = parent.childNodes;
console.log(children.length);
parent.appendChild(document.createElement('div'));
console.log(children.length); // length增加了1
在另一些情况下,NodeList 是一个静态集合,也就意味着随后对文档对象模型的任何改动都不会影响集合的内容。document.querySelectorAll 返回一个静态的 NodeList。
对NodeList对象使用Array.prototype.slice()方法可以将其转换为数组(类似arguments对象的转换),但是考虑到IE浏览器中的不同实现,做了一个兼容(手动枚举了所有成员):
function convertToArray(nodes) {
var arr = null;
try {
arr = Array.prototype.slice.call(nodes, 0); //针对非IE浏览器
} catch (e) {
arr = new Array();
for (var i = 0, len = nodes.length; i < len; i++) {
arr.push(nodes[i]);
}
}
return arr;
}