前面的话

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

NodeList

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

<div id="test"></div>
<script>
console.log(test.childNodes);//[]
//IE7-浏览器并未定义NodeList对象,会报错,其他浏览器返回true
console.log(test.childNodes instanceof NodeList)
</script>
<div id="test"></div>
<script>
console.log(document.querySelectorAll('div'));//[div#test]
//IE8-浏览器不支持querySelectorAll()方法,返回false,其他浏览器返回true
console.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);//false
var childNew = Array.prototype.slice.call(childN);
console.log(childNew instanceof Array);//true
</script>

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

<div id="test"></div>
<script>
var childN = test.childNodes;
console.log(childN instanceof Array);//false
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对象,会报错,其他浏览器返回true
console.log(childN instanceof HTMLCollection);
var tags =test.getElementsByTagName('div');
//IE7-浏览器并未定义HTMLCollection对象,会报错,其他浏览器返回true
console.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,它也具有动态性

  欢迎交流

深入理解javascript中的动态集合——NodeList、HTMLCollection和NamedNodeMap的更多相关文章

  1. 深入理解JavaScript中创建对象模式的演变(原型)

    深入理解JavaScript中创建对象模式的演变(原型) 创建对象的模式多种多样,但是各种模式又有怎样的利弊呢?有没有一种最为完美的模式呢?下面我将就以下几个方面来分析创建对象的几种模式: Objec ...

  2. 深入理解JavaScript中的属性和特性

    深入理解JavaScript中的属性和特性 JavaScript中属性和特性是完全不同的两个概念,这里我将根据自己所学,来深入理解JavaScript中的属性和特性. 主要内容如下: 理解JavaSc ...

  3. 深入理解javascript中执行环境(作用域)与作用域链

    深入理解javascript中执行环境(作用域)与作用域链 相信很多初学者对与javascript中的执行环境与作用域链不能很好的理解,这里,我会按照自己的理解同大家一起分享. 一般情况下,我们把执行 ...

  4. 深入理解JavaScript中的作用域和上下文

    介绍 JavaScript中有一个被称为作用域(Scope)的特性.虽然对于许多新手开发者来说,作用域的概念并不是很容易理解,我会尽我所能用最简单的方式来解释作用域.理解作用域将使你的代码脱颖而出,减 ...

  5. 理解JavaScript中的原型继承(2)

    两年前在我学习JavaScript的时候我就写过两篇关于原型继承的博客: 理解JavaScript中原型继承 JavaScript中的原型继承 这两篇博客讲的都是原型的使用,其中一篇还有我学习时的错误 ...

  6. 【干货理解】理解javascript中实现MVC的原理

    理解javascript中的MVC MVC模式是软件工程中一种软件架构模式,一般把软件模式分为三部分,模型(Model)+视图(View)+控制器(Controller); 模型:模型用于封装与应用程 ...

  7. 理解javascript中的策略模式

    理解javascript中的策略模式 策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换. 使用策略模式的优点如下: 优点:1. 策略模式利用组合,委托等技术和思想,有效 ...

  8. 深入理解javascript中的立即执行函数(function(){…})()

    投稿:junjie 字体:[增加 减小] 类型:转载 时间:2014-06-12 我要评论 这篇文章主要介绍了深入理解javascript中的立即执行函数,立即执行函数也叫立即调用函数,通常它的写法是 ...

  9. 转载 深入理解JavaScript中的this关键字

    转载原地址: http://www.cnblogs.com/rainman/archive/2009/05/03/1448392.html 深入理解JavaScript中的this关键字   1. 一 ...

随机推荐

  1. java基础

    属性是对象的特征,每个对象都有自己独立的属性值.一个对象的属性发生变化,不会影响另外一个对象的属性.属性是封装在对象之中的变量,是对象的成员.属性也叫成员变量. null表示一个变量没有指向任何对象. ...

  2. [RxJava]在学习RxJava中的错误理解

    关于RxJava语法的问题与理解   最近看到一个blog-RxJava 写到关于Observable数据异步加载的介绍.针对fromCallable和just操作符在使用上的问题来跟大家针对代码进行 ...

  3. 分布式系统:怎么简单地解释Paxos算法?从二段提交、三段提交讲到Paxos

    原文:https://www.quora.com/Distributed-Systems/What-is-a-simple-explanation-of-the-Paxos-algorithm 作者: ...

  4. Storm 中什么是-acker,acker工作流程介绍

    概述 我们知道storm一个很重要的特性是它能够保证你发出的每条消息都会被完整处理, 完整处理的意思是指: 一个tuple被完全处理的意思是: 这个tuple以及由这个tuple所导致的所有的tupl ...

  5. es6转es5

    一.在没有IDE情况下的转换 在"我的电脑->D盘”新建个文件夹es6,文件夹里新建一个文件es6.js. 打开命令行窗口 1.先全局安装babel-cli,输入命令 npm inst ...

  6. Python 字符串操作(string替换、删除、截取、复制、连接、比较、查找、包含、大小写转换、分割等)

    去空格及特殊符号 s.strip().lstrip().rstrip(',') 复制字符串 #strcpy(sStr1,sStr2) sStr1 = 'strcpy' sStr2 = sStr1 sS ...

  7. PHP的数组排序函数

    <?php class order{ /** * * 数组排序 * @param array $arr 例如: * array ( array ( 'deskId' => '460646' ...

  8. Ubuntu14.04或16.04下Hadoop及Spark的开发配置

    对于Hadoop和Spark的开发,最常用的还是Eclipse以及Intellij IDEA. 其中,Eclipse是免费开源的,基于Eclipse集成更多框架配置的还有MyEclipse.Intel ...

  9. java之数据结构之链表及包装类、包

    链表是java中的一种常见的基础数据结构,是一种线性表,但是不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针.与线性对应的一种算法是递归算法:递归算法是一种直接或间接的调用自身算法的过 ...

  10. Android零散

    2016-03-13 Android零散 ListView中嵌套GridView 要实现分组列表这样的效果:点击ListView中的分组名称,即展开此分组显示其包含的项目.使用ExpandableLi ...