6

我做了这个代码:

var foo=document.createElement("div");

var childs=foo.getElementsByTagName("*");

console.log(childs.length);//0 OK

var a=document.createElement("a");

foo.appendChild(a);

console.log(childs.length);//1 WTF?

小提琴:http: //jsfiddle.net/RL54Z/3/

我不必childs=foo.getElementsByTagName("*");在第五行和第六行之间写,以便childs.length更新。

怎么可能?

4

2 回答 2

3

如果您阅读文档,您不会感到惊讶

返回具有给定标签名称的元素列表。搜索指定元素下的子树,不包括元素本身。返回的列表是实时的,这意味着它会自动使用 DOM 树进行自我更新。因此,无需使用相同的元素和参数多次调用 element.getElementsByTagName。

于 2012-06-30T05:12:11.567 回答
3

DOM 中的大多数节点列表(例如从getElementsBy*querySelectorAll和中返回Node.childNodes)不是简单的数组,而是NodeList对象。 NodeList对象通常是“实时的”,因为对文档的更改会自动传播到Nodelist对象。(一个例外是来自 的结果querySelectorAll,它不是实时的!)

因此,正如您在示例中看到的,如果您检索所有a元素的 NodeList,然后将另一个a元素添加到文档中,该元素a将出现在您的 NodeList 对象中。

这就是为什么在对文档进行更改的同时迭代 NodeList 是不安全的。例如,这段代码将以令人惊讶的方式表现:

var NodeListA = document.getElementsByTagName('a');

for (var i=0; i<NodeListA.length; ++i) {
   // UNSAFE: don't do this!
   NodeListA[i].parentNode.removeChild(NodeListA[i]);
}

将会发生的是你最终会跳过元素!从 NodeList 的末尾向后迭代,或者将 NodeList 复制到普通数组(不会更新),然后使用它。

在Mozilla MDC 站点上阅读有关 NodeList 的更多信息。

于 2012-06-30T05:18:57.463 回答