getElementsByClassName的原生实现

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;
}

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

时间: 2024-10-14 05:33:53

getElementsByClassName的原生实现的相关文章

原生js方法document.getElementsByClassName在ie8及其以下的兼容性问题

原生js方法“document.getElementsByClassName”在ie8及其以下浏览器中,不能使用. 修改:加入兼容性判断,在需要用到该方法的位置修改为getClassNames方法. 代码如下: 原来方法: document.getElementsByClassName('tabs_div'): 这里的调用方法为:getClassNames('tabs_div' , 'div'): var divs = getClassNames('tabs_div' , 'div'); fun

js原生封装getClassName()方法-ie不支持getElementsByClassName,所以要自己实现获取类名为className的所有元素

<html> <head> <script type="text/javascript"> window.onload = function() { var topMenus = getClass('li','topMenu'); for(var i=0;i < topMenus.length; i++) { alert(topMenus[i].innerHTML); } } function getClass(tagName,classNam

js原生实现getElementsByClassName

document.getElementsByClassName = function(name){ try{ var tag = document.getElementsByTagName("*") || document.all; var array = []; for (var i = 0; i < tag.length; i++) { if(tag[i].className == name){ array.push(tag[i]); }; }; if(array.lengt

分分钟学会JavaScript原生

JavaScript是一种基于对象和事件驱动的客户端脚本语言 组成: ECMAScript---------------标准语法 Bom(browser Object Model) Dom(document)-------浏览器提供的扩充 API : application programming interface 应用程序接口 js引入,内部和外部,最好都放到body里的</body>标签前; 外部:<script src="" > </script&

深入理解javascript选择器API系列第二篇——getElementsByClassName

× 目录 [1]使用 [2]classList [3]扩展 前面的话 既然有getElementById()和getElementsByTagName()方法,为什么没有getElementsByClassName()呢?id属性.标签名.class属性并没有什么优劣之分啊.终于,HTML5新增了getElementsByClassName()方法,由于在CSS布局中类名的广泛使用,该方法正好切中痛点,使得通过类名选取元素不再麻烦,成为最欢迎的一个方法.接下来,本文将详细介绍该方法 使用 HTM

原生JS编写图片切换效果和点击按钮的样式变化

这两天更进一步的了解了JS,老师让我们用原生的js编写图片切换和改变点击按钮样式,就是让我们学会怎么去把一个问题拆分,怎么将一个大问题拆分成许多的小问题,再用函数封装起来.比如一个点击按钮,让其点击时背景色发生改变,点击另一个时,上一个按钮要变回原来本有的颜色:这个问题用jquery,一行代码就搞定,但是用原生js就得分三个部分来考虑: 1.添加改变背景的样式. 2.怎么获取到除了当前点击的按钮以外其他的兄弟节点. 3.怎么去除按钮的样式属性. 也讲了事件委托,实现了可以删除新添加的元素的功能.

图片轮播(左右切换)--js原生和jquery实现

图片轮播(左右切换)--js原生和jquery实现 左右切换的做法基本步骤跟 上一篇文章  淡入淡出 类似,只不过修改了一些特定的部分 (1)首先是页面的结构部分 对于我这种左右切换式 1.首先是个外围部分(其实也就是最外边的整体wrapper) 2.接着就是你设置图片轮播的地方(也就是一个banner吧) 3.然后是一个图片组(可以用新的div 也可以直接使用 ul-->li形式) 4.然后是图片两端的左箭头和右箭头5.然后是一个透明背景层,放在图片底部 6.然后是一个图片描述info层,放在

原生javascript解析xml文档

之前写过一篇 <javascript/jQuery解析或转换json和xml>链接是http://my.oschina.net/ososchina/blog/343748,这篇博客详细解释了json使用 JSON.js  window.eval() ,jQuery 与字符串互相转换的方法 ,顺便也说了一点jQuery解析xml文档的方法,这里着重论述javascript操作xml. 顺便提一下,今天做项目有一点问题,如何让服务程序接口返回的就是json,而不需要 使用 jQuery.ajax设

原生js的开发笔记

1.基本的dom操作 var a=document.getElementById('ma1').innerHTML;/获取html代码 alert(document.getElementById('ma1').getAttribute("id"));//获取属性 alert(document.getElementById('ma2').value);//获取值 2.获取select的值和文本信息,jquery的就非常简单了. var obj = document.getElementB