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

 更新时间:2010年07月09日 00:52:54   作者:  
在Web前端编程中,我们通常会通过document.getElementsByTagName的方法取出一组相同标签的dom元素。
比如:
复制代码 代码如下:

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 &lt; 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 &lt; 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 &lt; links.length; i++) {
anchors.push(links[i]);
}
}
for (i = 0; i &lt; 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 &lt; 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

相关文章

  • Table隔行变色的JavaScript代码

    Table隔行变色的JavaScript代码

    用js实现的table隔行变色,鼠标放上去有变色显示,需要的朋友可以参考下。
    2011-01-01
  • 浅谈js对象属性 通过点(.) 和方括号([]) 的不同之处

    浅谈js对象属性 通过点(.) 和方括号([]) 的不同之处

    下面小编就为大家带来一篇浅谈js对象属性 通过点(.) 和方括号([]) 的不同之处。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-10-10
  • JS识别浏览器类型(电脑浏览器和手机浏览器)

    JS识别浏览器类型(电脑浏览器和手机浏览器)

    本文给大家分享一段js代码关于识别浏览器的类型是手机浏览器还是电脑浏览器,有需要的朋友可以参考下本文
    2016-11-11
  • 微信小程序开发指南之图片压缩解决方案

    微信小程序开发指南之图片压缩解决方案

    在项目开发过程中遇到一个需要从小程序上传图片的需求,此需求实现起来并不难,下面这篇文章主要给大家介绍了关于微信小程序开发指南之图片压缩解决方案的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-08-08
  • 详解Javascript模板引擎mustache.js

    详解Javascript模板引擎mustache.js

    这篇文章主要为大家介绍了Javascript模板引擎mustache.js,mustache.js是一个简单强大的Javascript模板引擎,使用它可以简化在js代码中的html编写,压缩后只有9KB,非常值得在项目中使用,需要的朋友可以参考下
    2016-01-01
  • js 学习笔记(三)

    js 学习笔记(三)

    JavaScript的对象基础 本篇主要讲解本地对象Array的各种方法。
    2009-12-12
  • JS获取月份最后天数、最大天数与某日周数的方法

    JS获取月份最后天数、最大天数与某日周数的方法

    这篇文章主要介绍了JS获取月份最后天数、最大天数与某日周数的方法,涉及JavaScript针对日期与实现的相关操作技巧,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-12-12
  • VSCode中如何利用d.ts文件进行js智能提示

    VSCode中如何利用d.ts文件进行js智能提示

    这篇文章主要给大家介绍了关于VSCode中如何利用d.ts文件进行js智能提示的相关资料,文中通过图文以及示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2018-04-04
  • 时间戳转换为时间 年月日时间的JS函数

    时间戳转换为时间 年月日时间的JS函数

    这篇文章介绍了时间戳转换为时间 年月日时间的JS函数,有需要的朋友可以参考一下
    2013-08-08
  • javascript中this的四种用法

    javascript中this的四种用法

    在javascript当中每一个function都是一个对象,所以在这个里var temp=this 指的是function当前的对象。this是Javascript语言的一个关键字。它代表函数运行时,自动生成的一个内部对象,只能在函数内部使用。
    2015-05-05

最新评论