在一个折腾的javascript框架中querySelectorAll ,发现会报错。几经折腾发现原来querySelectorAll 返回的是一个Nodelist,而非数组(主要经常使用querySelectorAll ()[index]而造成错觉),联想到该方法在浏览器和IDE下会智能提示出item属性。
既然已经踩了坑,就记录下吧!
NodeList 对象是一个节点的集合,是由 Node.childNodes 和 document.querySelectorAll 返回的.
属性
length
- NodeList 对象中包含的节点个数.
方法
- item ( idx )
- 返回NodeList对象中指定索引的节点,如果索引越界,则返回null.等价的写法是nodeList[idx], 不过这种情况下越界访问将返回undefined.
描述
一个“有时实时”的集合
大多数情况下,NodeList 对象都是个实时集合。意思是说,如果文档中的节点树发生变化,则已经存在的 NodeList 对象也可能会变化。例如,Node.childNodes 是实时的:
var parent = document.getElementById('parent'); var child_nodes = parent.childNodes; console.log(child_nodes.length); // 如果假设结果是“2” parent.appendChild(document.createElement('div')); console.log(child_nodes.length); // 此时的输出是“3”
在另一些情况下,NodeList 是一个静态集合,也就意味着随后对文档对象模型的任何改动都不会影响集合的内容。document.querySelectorAll 返回一个静态的 NodeList。
特别是当你选择如何遍历 NodeList 中所有项,或缓存列表长度的时候,最好牢记这种区分。
为什么 NodeList 不是数组?
NodeList 对象在某些方面和数组非常相似,看上去可以直接使用从 Array.prototype 上继承的方法。然而,NodeList 没有这些类似数组的方法。
JavaScript 的继承机制是基于原型的。数组元素之所以有一些数组方法(比如 forEach 和 map),是因为它的原型链上有这些方法,如下:
myArray –> Array.prototype –> Object.prototype –> null (想要获取一个对象的原型链,可以连续的调用 Object.getPrototypeOf,直到原型链尽头).
forEach, map这些方式其实是 Array.prototype 这个对象的方法。
和数组不一样,NodeList的原型链是这样的:
myNodeList –> NodeList.prototype –> Object.prototype –> null
NodeList.prototype 只有一个 item 方法,没有 Array.prototype 上的那些方法,所以 NodeList 对象用不了它们。