getElementsByTagName("*") 总是更新的吗?

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

这是为什么呢?

2个回答

3
如果你阅读了文档,你就不会感到惊讶。
返回指定标签名的元素列表。在指定元素下面的子树中进行搜索,但不包括该元素本身。返回的列表是实时的,意味着它会自动更新DOM树。因此,不需要多次使用相同的元素和参数调用element.getElementsByTagName。

3
大多数DOM节点列表(例如从getElementsBy*querySelectorAllNode.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网站上了解更多关于NodeLists的信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接