Please note, this is a STATIC archive of website developer.mozilla.org from 03 Nov 2016, cach3.com does not collect or store any user information, there is no "phishing" involved.

NodeList 对象是一个节点的集合,是由 Node.childNodesdocument.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 对象用不了它们。

解决办法

一个解决办法就是把 Array.prototype 上的方法添加到 NodeList.prototype 上。可是,要注意扩展DOM对象的原型是非常危险的,尤其是在旧版本的Internet Explorer (6,7,8)中

var arrayMethods = Object.getOwnPropertyNames( Array.prototype );

arrayMethods.forEach( attachArrayMethodsToNodeList );

function attachArrayMethodsToNodeList(methodName)
{
  if(methodName !== "length") {
    NodeList.prototype[methodName] = Array.prototype[methodName];
  }
};
 
var divs = document.getElementsByTagName( 'div' );
var firstDiv = divs[ 0 ];

firstDiv.childNodes.forEach(function( divChild ){
  divChild.parentNode.style.color = '#0F0';
});

不扩展 DOM 对象原型的解决办法:

var forEach = Array.prototype.forEach;

var divs = document.getElementsByTagName( 'div' );
var firstDiv = divs[ 0 ];

forEach.call(firstDiv.childNodes, function( divChild ){
  divChild.parentNode.style.color = '#0F0';
});

请注意,在上面的代码中,将某个宿主对象 (如 NodeList) 作为 this 传递给原生方法 (如 forEach) 不能保证在所有浏览器中工作,已知在一些浏览器中会失败。

例子

遍历一个 NodeList 对象中的所有的节点可以使用如下代码:

for (var i = 0; i < myNodeList.length; ++i) {
  var item = myNodeList[i];  // 调用 myNodeList.item(i) 是没有必要的
}

不要尝试使用 for...in 或者 for each...in 来遍历一个NodeList 对象中的元素,因为如果你把上述两个属性也看成 elemnt 对象的话,NodeList 对象中的 length item 属性也会被遍历出来,这可能会导致你的脚本运行出错。此外,for...in 不能保证访问这些属性的顺序。

在支持 for...of 的浏览器中(比如 Firefox 13 及以后版本)for...of 循环将会正确的遍历 NodeList 对象

var list = document.querySelectorAll( 'input[type=checkbox]' );
for (var item of list) {
  item.checked = true;
}

将 NodeList 转换为 Array

有时候用类似数组的方法来处理 NodeList 里的内容会更加方便。这里有一种技术为了将 NodeList 对象转换为数组:

var div_list = document.querySelectorAll('div'); // 返回 NodeList
var div_array = Array.prototype.slice.call(div_list); // 将 NodeList 转换为数组

规范

文档标签和贡献者

标签: 
 此页面的贡献者: iplus26, Hawkeyes_Wind, teoli, jaka, ziyunfei, fishenal
 最后编辑者: iplus26,