NodeList对象转换成数组对象

NodeList是一个类似于数组,但又有区别于数组的一种类数组对象,为什么说NodeList类似于数组呢,因为NodeList对象,可以使用和数组取值方式同样的取值方式(中括号加下标取值),但是却又没有Array对象中常用的方法,slice,push,pop等,又不同于数组,是因为NodeList是一个实时变化的数组(大多数情况下,它是一个live的集合),即如果文档中的节点树发生变化,则已经存在的NodeList对象也可能会变化。

可以参考以下资料:NodeListNodeList 对象

概述

NodeList对象是一个节点的集合,通常是由getElementsByTagName, getElementsByTagNameNS, Node.childNodes, querySelectorAll, getElementsByClassName等方法返回的.
虽然说,NodeList大多数情况下,是一个live的集合,但并不是所有的NodeList对象,都是live的集合,比如这里querySelectorAll获取的NodeList集合,它就不是一个实时更新的集合。

你也可以点击查看:demo

我们也都知道,在所有的操作中,DOM操作是性能最差的,所以如果可以,就尽量的少使用DOM操作,这里的NodeList对象,如果是一个live的集合,那么在DOM结构进行变化时,很明显的会进行相关的DOM操作(引擎自己实现的),从而重新定义它的length的值,所以这样的代码并不是一个优雅的代码,可是querySelectorAll呢,这个方法在低版本的浏览器中是不支持的,所以,有时候,我们会把NodeList对象,转换成Array对象进行统一的处理。

问题

jQuery中,对于NodeList对象转换成Array对象,是这样处理的:


var links = document.getElementsByTagName('a');
var ArrayObj = [].slice.call(links);


经过这样的转换,把links变成一个数组,我们可以这样证明:


console.log(Object.getOwnPropertyNames(links.__proto__));
var ArrayObj = [].slice.call(links);
console.log(Object.getOwnPropertyNames(ArrayObj.__proto__));
console.log(ArrayObj.__proto__ === Array.prototype);      //true


看起来很不错的样子,可是问题出现了,当我们在IE8-的浏览器这样使用时,却出了问题,在NodeList转换成Array对象时,浏览器直接抛出一个错误:

SCRIPT5014:Array.prototype.slice: ‘this’ 不是 JavaScript 对象

这是为什么?因为在IE8-的浏览器中,HTMLDOM对象,不是继承自Object对象的?这里关于为什么DOM对象不继承自Object对象,就会导致无法使用Array对象中的方法,根本原因,不能明了。

求助:如果您对这里出现这个问题的原因,有一个本质的认识,请不吝赐教,非常感谢

而从抛出的错误的原因可以看出,是在Array.prototype.slice函数执行时,内部的this对象调用了一个属于Object对象的方法或者属性,而这个方法或者属性是IE8-DOM对象中不存在的一个。具体是哪个属性或者方法才会出现这个问题,未知~~

当然,这里出了这个问题,就会有相应的解决方法,方法也算是很简单,只要重写一下就行了,例如下面的样子,最简单的写法:


Array.prototype.slice = function(){
    var ele = this,
	i = 0,
	len = ele.length,
	res = [];
    for(;i<len;i++){
	res.push(ele[i]);
    }
    return res;
}

var links = document.getElementsByTagName('a');
console.log([].slice.call(links));


感觉这里有点扯,能力有限,暂时只能理解到这里,更深层次的原因,继续寻找,也欢迎赐教!

补充

2014-6-21补充:NodeList这种类型,之所以被称之为live数组,也是因为它们的另外的名字,类数组,想想类数组是什么,想想数组时属于什么样的类型,数组是Array类型,是一个引用类型,类数组是一个Object类型,Object也是属于引用类型。引用类型有一个特点就是,如果不重新赋值,那么对于引用类型的更改,都是在更改同一个引用类型的。

例如:


var a = [];
a[0] = 1;
console.log(a[0]); //1


我认为,live类的实时更新到元素中去,它的根本原因,就在于,它们获取到的值,是一个类数组,是一个引用类型的数据类型。

暂时这么理解,如果有任何错误,请指教,谢谢!

本文地址:http://www.zhangyunling.com/?p=93

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>