JavaScript 中动态节点集合(NodeList/HTMLCollection)的陷阱与处理

作者:代码拾荒

时间:2026-10-24

浏览:652

本文深入解析 JavaScript 中 NodeList 和 HTMLCollection 的动态特性。由于这些集合会随 DOM 结构变化而自动更新,直接使用索引遍历可能导致逻辑错误。文章提供了将节点转换为数组或使用 firstChild 循环处理的两种正确方案,并对比了不同浏览器下的实现差异。

文章目录
<!doctype html> <html lang="en"> <head> <meta charset="utf-8" /> <meta content="IE=8" http-equiv="X-UA-Compatible"/> <title>节点集合 by 司徒正美 </title> <style> #aaa { padding:10px; border:1px solid red; } p { border:1px solid blue; } </style>  </head> <body> <div id="aaa"> <p class="aaaa">司徒正美</p> <p class="aaaa">司徒正美</p> <p class="aaaa">司徒正美</p> <p class="aaaa">司徒正美</p> <p class="aaaa">司徒正美</p> </div> </body> </html> 

[Ctrl+A 全选 注:引入外部Js需再刷新一下页面才能执行]


NodeList 的动态特性与遍历陷阱

若预先将节点列表转换为数组,则可避免后续问题。


代码如下:

 
window.onload = function(){
var d = document.createDocumentFragment();
var div = document.getElementById("aaa");
var c = div.childNodes;
var arr = [];
for(var i=0,n=c.length;i<n;i++){
arr.push(c[i])
} 
for(var i=0,n=arr.length;i<n;i++){
alert(arr[i] + " "+ i)
d.appendChild(arr[i])
} 
div.parentNode.replaceChild(d,div)
} 

 <!doctype html> <html lang="en"> <head> <meta charset="utf-8" /> <meta content="IE=8" http-equiv="X-UA-Compatible"/> <title>节点集合 by 司徒正美 </title> <style> #aaa { padding:10px; border:1px solid red; } p { border:1px solid blue; } </style>  </head> <body> <div id="aaa"> <p class="aaaa">司徒正美</p> <p class="aaaa">司徒正美</p> <p class="aaaa">司徒正美</p> <p class="aaaa">司徒正美</p> <p class="aaaa">司徒正美</p> </div> </body> </html> 

[Ctrl+A 全选 注:引入外部Js需再刷新一下页面才能执行]


显然,nodeList 具备数组所没有的怪异特性。由运行框 2 可知,将节点 appendChild 至文档碎片时,实则是将其从 DOM 树中剥离,nodeList 必定追踪此变化并动态更新自身,而线性递增的 i 无法对应正确节点的索引!故每次获取其 firstChild 即可。


代码如下:

 
window.onload = function(){
var d = document.createDocumentFragment();
var div = document.getElementById("aaa");
var c = div.childNodes;
while(c.length) d.appendChild(c[0])//每次只取它第一个节点,直到取空
div.parentNode.replaceChild(d,div)
} 

 <!doctype html> <html lang="en"> <head> <meta charset="utf-8" /> <meta content="IE=8" http-equiv="X-UA-Compatible"/> <title>变态的childNodes by 司徒正美 </title> <style> #aaa { padding:10px; border:1px solid red; } p { border:1px solid blue; } </style>  </head> <body> <div id="aaa"> <p class="aaaa">司徒正美</p> <p class="aaaa">司徒正美</p> <p class="aaaa">司徒正美</p> <p class="aaaa">司徒正美</p> <p class="aaaa">司徒正美</p> </div> </body> </html> 

[Ctrl+A 全选 注:引入外部Js需再刷新一下页面才能执行]


HTMLCollection 与跨浏览器差异

此外,由 getElementsByTagName 获取的 HTMLCollection 也具备相同特性,处理此类节点集合时需格外谨慎。


 <!doctype html> <html lang="en"> <head> <meta charset="utf-8" /> <meta content="IE=8" http-equiv="X-UA-Compatible"/> <title>HTMLCollection by 司徒正美 </title> <style> #aaa { padding:10px; border:1px solid red; } p { border:1px solid blue; } </style>  </head> <body> <div id="aaa"> <p class="aaaa">司徒正美</p> <p class="aaaa">司徒正美</p> <p class="aaaa">司徒正美</p> <p class="aaaa">司徒正美</p> <p class="aaaa">司徒正美</p> </div> </body> </html> 

[Ctrl+A 全选 注:引入外部Js需再刷新一下页面才能执行]


这两种节点集合在不同浏览器中的实现存在差异。例如,在标准浏览器中可使用 Array.prototype.slice.call 将其转换为原生数组,而在 IE 中则会报错。标准浏览器的此类集合拥有 hasOwnProperty 与 valueOf 方法,而 IE 则不具备。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章