2012-06-30 27 views
5

Tôi đã thực hiện mã này:getElementsByTagName ("*") luôn được cập nhật?

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? 

Một fiddle: http://jsfiddle.net/RL54Z/3/

Tôi không phải viết childs=foo.getElementsByTagName("*"); giữa thứ năm và thứ sáu dòng để childs.length được cập nhật.

Làm cách nào?

Trả lời

3

Hầu hết các danh sách của các nút trong DOM (ví dụ trở về từ getElementsBy*, querySelectorAll, và Node.childNodes) không Mảng đơn giản nhưng khá NodeList đối tượng. NodeList đối tượng thường "sống", trong đó các thay đổi đối với tài liệu được tự động truyền đến đối tượng Nodelist. (Một ngoại lệ là kết quả từ querySelectorAll, đó là không sống!)

Như bạn có thể thấy trong ví dụ của bạn, nếu bạn lấy một NodeList của tất cả a yếu tố, sau đó thêm một yếu tố khác a vào tài liệu, mà a sẽ xuất hiện trong đối tượng NodeList của bạn.

Đây là lý do tại sao không an toàn để lặp qua NodeList trong khi thực hiện thay đổi đối với tài liệu cùng một lúc. Ví dụ: mã này sẽ hoạt động theo những cách đáng ngạc nhiên:

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

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

Điều gì sẽ xảy ra là bạn sẽ kết thúc phần tử bỏ qua! Hoặc lặp lại từ cuối NodeList, hoặc sao chép NodeList thành một mảng đơn giản (sẽ không cập nhật) và sau đó làm việc với nó.

Đọc thêm về NodeLists tại Mozilla MDC site.

3

Nếu bạn đọc documentation bạn sẽ không ngạc nhiên

Trả về một danh sách các yếu tố với tên thẻ nhất định. Cây con bên dưới phần tử được chỉ định được tìm kiếm, loại trừ chính phần tử đó. Danh sách trả về là trực tiếp, có nghĩa là nó tự động cập nhật với cây DOM. Do đó, không cần phải gọi nhiều lần element.getElementsByTagName với cùng một phần tử và đối số.

Các vấn đề liên quan