getElementsByTagName("*")总是更新?

Mag*_*eek 5 javascript dom getelementsbytagname

我已经制作了这段代码:

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?
Run Code Online (Sandbox Code Playgroud)

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

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

怎么会这样?

Fra*_*ila 3

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

正如您在示例中看到的,如果您检索所有元素的 NodeList a,然后将另一个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]);
}
Run Code Online (Sandbox Code Playgroud)

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

Mozilla MDC 站点阅读有关 NodeLists 的更多信息。