getElementsByClassName的原生实现

通过Class Name获取一个对象的数组
服务器君一共花费了284.871 ms进行了6次数据库查询,努力地为您提供了这个页面。
试试阅读模式?希望听取您的建议

DOM 提供了一个名为 getElementById() 的方法,这个方法将返回一个对象,这个对象就是参数 id 所对应的元素节点。另外,getElementByTagName() 方法会返回一个对象的数组,每一个对象分别对应着文档里有给定标签的一个元素。这个方法的参数是 html 标签的名字。现在我们考虑一个问题,能不能通过标签的类名class name来获取该对象呢?下面是这个猜想的程序实现(支持多个class查询和在某个范围内进行查询):

/*
 * 根据元素clsssName得到元素集合
 * @param fatherId 父元素的ID,默认为document
 * @tagName 子元素的标签名
 * @className 用空格分开的className字符串
 */
function getElementsByClassName(fatherId,tagName,className){
	node = fatherId&&document.getElementById(fatherId) || document;
	tagName = tagName || "*";
	className = className.split(" ");
	var classNameLength = className.length;
	for(var i=0,j=classNameLength;i<j;i++){
		//创建匹配类名的正则
		className[i]= new RegExp("(^|\\s)" + className[i].replace(/\-/g, "\\-") + "(\\s|$)"); 
	}
	var elements = node.getElementsByTagName(tagName);
	var result = [];
	for(var i=0,j=elements.length,k=0;i<j;i++){//缓存length属性
		var element = elements[i];
		while(className[k++].test(element.className)){//优化循环
			if(k === classNameLength){
				result[result.length] = element;
				break;
			}	
		}
		k = 0;
	}
	return result;
}

好,我们来测试一下:

<div id="container">
  	<span class="aaa zzz ccc"></span>
  	<div class="aaa bbb ccc"></div>
</div>
<div class="aaa bbb ccc"></div>
window.onload = function(){
	alert(getElementsByClassName(document,"div","aaa ccc").length);//2
	alert(getElementsByClassName("container","div","aaa ccc").length);//1
	alert(getElementsByClassName("container","span","aaa zzz").length);//1
}

正确的得到了结果。

有人会问,原生的方法调用效率是最高的,有很多浏览器已经将实现了getElementsByClassName这个方法,那为什这里没有先调用原生的再调用自定义的呢?

对,原生的效率是很高,它支持多个class条件的查询,但是最大的问题是他不支持getElementsByClassName("container","div","aaa ccc"),这种在指定标签中查找指定元素为指定class的情况。所以,这里舍弃了原生的方法调用。

在代码中,你会看到我将数组的length缓存了起来,这样可以提高效率。其实上,在这里有一个很隐蔽的问题,就是数组访问length属性和HtmlCollection访问length有很在的区别。在数组中,length是一个普通的属性,访问时不会进行额外的操作,在来看看HTMLCollection,我们常常将HTMLCollection当作数组来使用,但实际上,它是一个根据DOM结构自动变化的实体对象。每次访问一个HTMLCollection对象的属性时,他都会对DOM内所有的节点进行一次完整的匹配。也就是说,每次访问HtmlCollection对象的length时,都会更新一次集合对象,性能上消耗很大。所以一般情况之下,这种HtmlCollection的循环操作,都是建议缓存length的。

小插曲

这是关于往数组里放元素的方式间,效率比较的问题。来看一下代码:

//方式一
var arr = [];
var start = new Date();
for(var i=0;i<100000;i++){
	arr.push(i);
}
//方式二
var arr = [];
var start = new Date();
for(var i=0;i<100000;i++){
	arr[arr.length]=i;
}

猜猜看,哪种效率更高呢!经过测试,第二种方式的效率要高于第一种。好了,不多说的,这个函数简单实用,代码上我也写了注释,看应该已经没有什么问题了。

本文地址:http://www.nowamagic.net/librarys/veda/detail/195,欢迎访问原出处。

不打个分吗?

转载随意,但请带上本文地址:

http://www.nowamagic.net/librarys/veda/detail/195

如果你认为这篇文章值得更多人阅读,欢迎使用下面的分享功能。
小提示:您可以按快捷键 Ctrl + D,或点此 加入收藏

大家都在看

阅读一百本计算机著作吧,少年

很多人觉得自己技术进步很慢,学习效率低,我觉得一个重要原因是看的书少了。多少是多呢?起码得看3、4、5、6米吧。给个具体的数量,那就100本书吧。很多人知识结构不好而且不系统,因为在特定领域有一个足够量的知识量+足够良好的知识结构,系统化以后就足以应对大量未曾遇到过的问题。

奉劝自学者:构建特定领域的知识结构体系的路径中再也没有比学习该专业的专业课程更好的了。如果我的知识结构体系足以囊括面试官的大部分甚至吞并他的知识结构体系的话,读到他言语中的一个词我们就已经知道他要表达什么,我们可以让他坐“上位”毕竟他是面试官,但是在知识结构体系以及心理上我们就居高临下。

所以,阅读一百本计算机著作吧,少年!

《算法导论(原书第2版)》 科曼(Cormen T.H.) (作者), 等 (作者, 译者), 潘金贵 (译者)

《算法导论(原书第2版)》一书深入浅出,全面地介绍了计算机算法。对每一个算法的分析既易于理解又十分有趣,并保持了数学严谨性。本书的设计目标全面,适用于多种用途。涵盖的内容有:算法在计算中的作用,概率分析和随机算法的介绍。本书专门讨论了线性规划,介绍了动态规划的两个应用,随机化和线性规划技术的近似算法等,还有有关递归求解、快速排序中用到的划分方法与期望线性时间顺序统计算法,以及对贪心算法元素的讨论。本书还介绍了对强连通子图算法正确性的证明,对哈密顿回路和子集求和问题的NP完全性的证明等内容。全书提供了900多个练习题和思考题以及叙述较为详细的实例研究。

更多计算机宝库...