2012-06-30 31 views
5

我有此代碼: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? 

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

我沒有寫的第五和第六行,以便childs.length更新之間childs=foo.getElementsByTagName("*");

這怎麼可能?

回答

3

大多數在DOM節點的列表(例如,從getElementsBy*querySelectorAllNode.childNodes返回)不是簡單的陣列而是NodeList對象。 NodeList對象通常是「活的」,因爲對文檔的更改會自動傳播到Nodelist對象。 (一個例外是從querySelectorAll的結果,這是活了!)

所以你可以在你的例子看,如果你檢索所有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]); 
} 

會發生什麼是你最終會跳過元素!從NodeList的末尾向後迭代,或者將NodeList複製到一個普通的Array(它不會更新),然後使用它。

Mozilla MDC site處瞭解更多關於NodeLists的信息。

3

如果你讀了documentation你會不會感到驚訝

返回具有給定標記名稱的元素列表。搜索指定元素下的子樹,排除元素本身。返回的列表是實時的,這意味着它會自動使用DOM樹進行自我更新。因此,不需要使用相同的元素和參數多次調用element.getElementsByTagName。