首页 > 代码库 > 深入理解javascript中的动态集合——NodeList、HTMLCollection和NamedNodeMap

深入理解javascript中的动态集合——NodeList、HTMLCollection和NamedNodeMap

×
目录
[1]NodeList [2]HTMLCollection [3]NamedNodeMap[4]注意事项

前面的话

  一说起动态集合,多数人可能都有所了解。但是,如果再深入些,有哪些动态集合,以及这些动态集合有什么表现、区别和联系?可能好多人就要摇头了。本文就javascript中的动态集合做详细介绍

 

NodeList

  NodeList实例对象是一个类数组对象,它的成员是节点对象,包括childNodes和querySelectorAll()方法返回值

<div id="test"></div><script>console.log(test.childNodes);//[]//IE7-浏览器并未定义NodeList对象,会报错,其他浏览器返回trueconsole.log(test.childNodes instanceof NodeList)</script>
<div id="test"></div><script>console.log(document.querySelectorAll(div));//[div#test]//IE8-浏览器不支持querySelectorAll()方法,返回false,其他浏览器返回trueconsole.log(document.querySelectorAll(div) instanceof NodeList)</script>

  动态集合是指当DOM结构的变化能够自动反映到所保存的对象中

<div id="test"></div><script>var childN = test.childNodes;console.log(childN);//[]test.appendChild(document.createElement(div));console.log(childN);//[div]</script>

静态

  [注意]NodeList并不都是动态集合,其中querySelectorAll()返回值就是静态集合NodeStaticList

<div id="test"></div><script>var seles = test.querySelectorAll(div);console.log(seles);//[]test.appendChild(document.createElement(div));console.log(seles);//[]console.log(test.querySelectorAll(div));//[div]</script>

数组

  由于NodeList是类数组对象,并不是真正的数组对象,可以使用slice()方法将其变成真正的数组

<div id="test"></div><script>var childN = test.childNodes;console.log(childN instanceof Array);//[]var childNew = Array.prototype.slice.call(childN);console.log(childNew instanceof Array);//[div]</script>

  但是,由于IE8-浏览器将NodeList实现为一个COM对象,不能使用Array.prototype.slice()方法,必须手动枚举所有成员

<div id="test"></div><script>var childN = test.childNodes;console.log(childN instanceof Array);//[]function convertToArray(nodes){    var array = null;    try{        array = Array.prototype.slice.call(nodes)    }catch(ex){        array = [];        var len = nodes.length;        for(var i = 0; i < len; i++){            array.push(nodes[i]);        }    }    return array;}var childNew =convertToArray(childN);console.log(childNew instanceof Array);//true</script>

 

HTMLCollection

  HTMLCollection对象与NodeList对象类似,也是节点的集合,返回一个类数组对象。但二者有不同之处

  NodeList集合主要是Node节点的集合,而HTMLCollection集合主要是Element元素节点的集合。Node节点共有12种,Element元素节点只是其中一种。关于12种节点类型的详细信息移步至此

  HTMLCollection集合主要包括getElementsByTagName()、getElementsByClassName()、getElementsByName()等方法的返回值,以及children、document.links、document.forms等元素集合

<div id="test"></div><script>var childN = test.children;//IE7-浏览器并未定义HTMLCollection对象,会报错,其他浏览器返回trueconsole.log(childN instanceof HTMLCollection);var tags =test.getElementsByTagName(div);//IE7-浏览器并未定义HTMLCollection对象,会报错,其他浏览器返回trueconsole.log(tags instanceof HTMLCollection);</script>    

动态

  与NodeList对象不同,所有的HTMLCollection对象都是动态的

<div id="test"></div><script>var childN = test.children;var tags =test.getElementsByTagName(div);console.log(childN,tags);//[]、[]test.innerHTML = <div></div>;console.log(childN,tags);//[div]、[div]</script>    

  [注意]与NodeList对象类似,要想变成真正的数组Array对象,需要使用slice()方法,在IE8-浏览器中,则必须手动枚举所有成员

 

NamedNodeMap

  可能一些人没有听过NamedNodeMap对象,该对象的常见实例对象是attributes属性

<div id="test"></div><script>var attrs = test.attributes;console.log(attrs instanceof NamedNodeMap);//true</script>

动态

  该对象也是一个动态集合

<div id="test"></div><script>var attrs = test.attributes;console.log(attrs);//NamedNodeMap {0: id, length: 1}test.setAttribute(title,123);console.log(attrs);//NamedNodeMap {0: id, 1: title, length: 2}</script>

 

注意事项

  动态集合是个很实用的概念,但在使用循环时一定要千万小心。可能会因为忽略集合的动态性,造成死循环

var divs = document.getElementsByTagName("div");for(var i = 0 ; i < divs.length; i++){    document.body.appendChild(document.createElement("div"));}

  在上面代码中,由于divs是一个HTMLElement集合,divs.length会随着appendChild()方法,而一直增加,于是变成一个死循环

  为了避免此情况,一般地,可以写为下面形式

var divs = document.getElementsByTagName("div");for(var i = 0,len = divs.length; i < len; i++){    document.body.appendChild(document.createElement("div"));}

   一般地,要尽量减少访问NodeList、HTMLCollection、NamedNodeMap的次数。因为每次访问它们,都会运行一次基于文档的查询。所以,可以考虑将它们的值缓存起来

 

最后

  NodeList是节点的集合,HTMLCollection是元素节点的集合,NamedNodeMap是特性节点的集合,它们都是类数组对象

  对了,还有一个更经典的类数组对象——函数内部的arguments,它也具有动态性

  欢迎交流

<script type="text/javascript">// 0){ return; } if(select[i].getBoundingClientRect().top <= 0 && select[i+1]){ if(select[i+1].getBoundingClientRect().top > 0){ change(oCon.children[i+2]) } }else{ change(oCon.children[select.length+1]) } }}document.body.onmousewheel = wheel;document.body.addEventListener(‘DOMMouseScroll‘,wheel,false);var oCon = document.getElementById("content");var close = oCon.getElementsByTagName(‘span‘)[0];close.onclick = function(){ if(this.innerHTML == ‘显示目录‘){ this.innerHTML = ‘ב; this.style.background = ‘‘; oCon.style.border = ‘2px solid #ccc‘; oCon.style.width = ‘‘; oCon.style.height = ‘‘; oCon.style.overflow = ‘‘; oCon.style.lineHeight = ‘30px‘; }else{ this.innerHTML = ‘显示目录‘; this.style.background = ‘#3399ff‘; oCon.style.border = ‘none‘; oCon.style.width = ‘60px‘; oCon.style.height = ‘30px‘; oCon.style.overflow = ‘hidden‘; oCon.style.lineHeight = ‘‘; }}for(var i = 2; i < oCon.children.length; i++){ oCon.children[i].onmouseover = function(){ this.style.color = ‘#3399ff‘; } oCon.children[i].onmouseout = function(){ this.style.color = ‘inherit‘; if(this.mark){ this.style.color = ‘#3399ff‘; } } oCon.children[i].onclick = function(){ change(this); } }function change(_this){ for(var i = 2; i < oCon.children.length; i++){ oCon.children[i].mark = false; oCon.children[i].style.color = ‘inherit‘; oCon.children[i].style.textDecoration = ‘none‘; oCon.children[i].style.borderColor = ‘transparent‘; } _this.mark = true; _this.style.color = ‘#3399ff‘; _this.style.textDecoration = ‘underline‘; _this.style.borderColor = ‘#2175bc‘; }// ]]></script>

深入理解javascript中的动态集合——NodeList、HTMLCollection和NamedNodeMap