在javascript将NodeList作为Array数组处理的方法


Posted in Javascript onJuly 09, 2010

比如:

var anchors = document.getElementsByTagName("a"); 
for (i = 0; i < anchors.length; i++) { 
var ele=anchors[i];//取某一个元素 
//some code here 
}

上面的代码表示获取文档中的所有链接元素,然后遍历做一些事情。
也许你会问,通过这种方法获取的这一组dom元素不就是一个数组吗?你看,你都可以直接获取它的length属性,还可以根据索引取到对应的单独元素,根据大牛的著名鸭子理论,它像鸭子一样行走(有length属性),像鸭子一样叫唤(根据索引取值),那么它就是一只鸭子。结论不言自明了吧?
如果,你已经对javascript稍微有过深入的了解,有length属性,可以索引取值,一定是数组吗,好像arguments也会这么一手吧,arguments是数组?虽然在实际开发的时候,我们把它当做普通数组来操作,length和for循环使用的不亦乐乎,而且并不见得会出错。
但是,它真的不是数组(Array),而是NodeList。NodeList不是数组。
What a surprise,right?

1、NodeList为什么不是数组?

验证NodeList是不是数组,最直接的方法也许是试一下Array专有的push和pop大法:

var anchors = document.getElementsByTagName("a"); 
var newEle = document.createElement("a");//新建一个a元素 
anchors.push(newEle);//push 
var element= anchors.pop();//pop

您可以自己测试一下,上面的代码不管是push还是pop方法,无一例外的会提示你没有push或者pop方法。还有疑问吗?这样就结束了吗?这种片面的测试反倒使楼猪无法高枕无忧心安理得了。我们完全可以像证明arguments不是数组一样,也用同样的方法证明NodeList不是数组。看下面的代码吧:
Array.prototype.testNodeList = "test nodelist"; //数组添加原型属性 
function funcNodeList() { 
var links = document.getElementsByTagName("a"); 
alert(links.testNodeList); 
} 
function test() { 
alert(new Array().testNodeList); //test nodelist 
funcNodeList(); //#ff0000? what the hell is that? 
} 
test(); //测试一下

通过上面的分析,我们可以肯定NodeList不是数组(Array)了。那么如何按照我们操作集合的习惯操作NodeList呢?

2、像操作Array一样操作NodeList

既然NodeList有length,可以for循环索引取值,转换成数组还不是轻而易举?哈哈,最直接的思路是这样的:g

var arr = new Array(); 
var anchors = document.getElementsByTagName("a") 
for (var i = 0; i < anchors.length; i++) { 
var ele = anchors[i]; 
arr.push(ele); //arr就是我们要的数组 
}

明扼要说明一下吧:先new一个Array,遍历NodeList,然后将每一个单独的元素push到数组变量里,最后操作数组变量,over。有没有智商受辱的感觉?
上面不是跟您开玩笑,因为下面是楼猪在网上google到的,两行代码就可以将NodeList转换成Array来使用了:
var anchors = document.getElementsByTagName("a"); 
var arr = Array.prototype.slice.call(anchors); //非ie浏览器正常

但是,最最遗憾的事情发生了:上面的代码在万恶的IE下不能正常工作,IE会给你提示: 缺少 JScript 对象。
你可能会对上面的一大段分析不屑一顾,认为没有必要将NodeList转换成Array来操作。其实,楼猪个人也认为,不管在哪种编程语言里,类型转换都是非常不明智的行为。最常见的比如c#里的装箱和拆箱,数值型数据转换,有性能问题,一不小心还会触雷。但是为什么楼猪单独要把NodeList当做Array来处理呢?因为动态改变NodeList的时候,直接操作NodeList很可能会误闯禁区而浑然不觉。下面举个例子:
(1)、html文档片段

<div id="divAnchor">
<a href="http://www.cnblogs.com/jeffwongishandsome/">link test</a>
</div>
(2)、javascript测试代码

var anchors = document.getElementsByTagName("a"); 
for (i = 0; i < anchors.length; i++) { 
var ele= document.createElement("a"); 
ele.setAttribute("href", "http://www.cnblogs.com/jeffwongishandsome/"); 
ele.appendChild(document.createTextNode("new link test")); 
document.getElementById("divAnchor").appendChild(ele); //div附加一个新链接 
}

在文档加载结束后,执行上面的脚本。我们的本意是在div内,已经存在的a元素后再附加一个a元素。但是,您可以运行一下,浏览器crash掉了吧?楼猪这里IE直接挂掉,FF提示脚本正忙,是否停止脚本运行,点击停止后,页面内已经生成了n多个a链接。其实我们可以大胆分析出原因来:for循环NodeList(前提:for循环内部添加了新的元素使nodelist长度发生了变化。感谢陈童鞋超群的建议),它的length会不断变化上升,循环循环再循环,最后成了个死循环。而用下面的代码,和我们预期的效果是一样一样的:
var links = document.getElementsByTagName("a"); 
var anchors = null; //数组 
try { 
anchors = Array.prototype.slice.call(links); 
} 
catch (e) { //兼容ie 
anchors = new Array(); 
for (var i = 0; i < links.length; i++) { 
anchors.push(links[i]); 
} 
} 
for (i = 0; i < anchors.length; i++) { //数组循环 安全多了 
var ele = document.createElement("a"); 
ele.setAttribute("href", "http://www.cnblogs.com/jeffwongishandsome/"); 
ele.appendChild(document.createTextNode("new link test")); 
document.getElementById("divAnchor").appendChild(ele); //div附加一个新链接 
}

那么你可能会问,不转换不行吗?没有那么死板,当然是可以的,只要对我们平时熟悉的编码习惯稍微动点小手术就可以了:
var anchors = document.getElementsByTagName("a"); 
var len = anchors.length; //定义一个变量 
for (i = 0; i < len; i++) { //对局部变量len进行循环 
var ele = document.createElement("a"); 
ele.setAttribute("href", "http://www.cnblogs.com/jeffwongishandsome/"); 
ele.appendChild(document.createTextNode("new link test")); 
document.getElementById("divAnchor").appendChild(ele); //div附加一个新链接 
}

到这里,不管有无疑问,实际编程如何取舍,楼猪都要感谢您的阅读了。期待指点。
者:Jeff Wong
Javascript 相关文章推荐
懒就要懒到底——鼠标自动点击(含时间判断)
Feb 20 Javascript
多选列表框动态添加,移动,删除,全选等操作的简单实例
Jan 13 Javascript
使用AngularJS对路由进行安全性处理的方法
Jun 18 Javascript
Angular中$compile源码分析
Jan 28 Javascript
使用React实现轮播效果组件示例代码
Sep 05 Javascript
二维码图片生成器QRCode.js简单介绍
Aug 18 Javascript
详解nuxt sass全局变量(公共scss解决方案)
Jun 27 Javascript
浅谈Vue服务端渲染框架Nuxt的那些事
Dec 21 Javascript
Vue.js递归组件实现组织架构树和选人功能案例分析
Jul 03 Javascript
ES6对象操作实例详解
May 23 Javascript
JavaScript中CreateTextFile函数
Aug 30 Javascript
解决vue scoped scss 无效的问题
Sep 04 Javascript
jquery multiSelect 多选下拉框
Jul 09 #Javascript
IE8 chrome中table隔行换色解决办法
Jul 09 #Javascript
jQuery EasyUI NumberBox(数字框)的用法
Jul 08 #Javascript
JSON.parse 解析字符串出错的解决方法
Jul 08 #Javascript
location.href 在IE6中不跳转的解决方法与推荐使用代码
Jul 08 #Javascript
JQuery从头学起第三讲
Jul 06 #Javascript
一步一步制作jquery插件Tabs实现过程
Jul 06 #Javascript
You might like
php AJAX实例根据邮编自动完成地址信息
2008/11/23 PHP
php生成的html meta和link标记在body标签里 顶部有个空行
2010/05/18 PHP
PHP实现提取一个图像文件并在浏览器上显示的代码
2012/10/06 PHP
Fine Uploader文件上传组件应用介绍
2013/01/06 PHP
使用php+apc实现上传进度条且在IE7下不显示的问题解决方法
2013/04/25 PHP
360通用php防护代码(使用操作详解)
2013/06/18 PHP
php 截取中英文混合字符串的方法
2018/05/31 PHP
PHP实现的分解质因数操作示例
2018/08/01 PHP
PHP语言对接抖音快手小红书视频/图片去水印API接口源码
2020/08/11 PHP
基于JQuery的6个Tab选项卡插件
2010/09/03 Javascript
Javascript表单特效之十大常用原理性样例代码大总结
2016/07/12 Javascript
JS实现焦点图轮播效果的方法详解
2016/12/19 Javascript
js基于FileSaver.js 浏览器导出Excel文件的示例
2017/08/15 Javascript
Vue中建立全局引用或者全局命令的方法
2017/08/21 Javascript
使用vue实现一个电子签名组件的示例代码
2020/01/06 Javascript
JavaScript中的this妙用实例分析
2020/05/09 Javascript
JS绘图Flot如何实现可选显示曲线图功能
2020/10/16 Javascript
PHP魔术方法__ISSET、__UNSET使用实例
2014/11/25 Python
JS设计模式之责任链模式实例详解
2018/02/03 Python
Python3.5 Json与pickle实现数据序列化与反序列化操作示例
2019/04/29 Python
python 批量解压压缩文件的实例代码
2019/06/27 Python
ML神器:sklearn的快速使用及入门
2019/07/11 Python
Django User 模块之 AbstractUser 扩展详解
2020/03/11 Python
使用Keras预训练模型ResNet50进行图像分类方式
2020/05/23 Python
Python中logging日志的四个等级和使用
2020/11/17 Python
阿里巴巴国际站:Alibaba.com
2016/07/21 全球购物
苹果中国官方网站:Apple中国
2016/07/22 全球购物
土耳其时尚潮流在线购物网站:Trendyol
2017/10/10 全球购物
New Balance俄罗斯官方网上商店:购买运动鞋
2020/03/02 全球购物
了解AppleShare protocol(AppleShare协议)吗
2015/08/28 面试题
护士试用期自我鉴定
2014/02/08 职场文书
竞争上岗实施方案
2014/03/21 职场文书
迟到检讨书2000字(精选篇)
2014/10/07 职场文书
解决Pytorch dataloader时报错每个tensor维度不一样的问题
2021/05/28 Python
MySQL深度分页(千万级数据量如何快速分页)
2021/07/25 MySQL
Zabbix对Kafka topic积压数据监控的问题(bug优化)
2022/07/07 Servers