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;
}
猜猜看,哪种效率更高呢!经过测试,第二种方式的效率要高于第一种。好了,不多说的,这个函数简单实用,代码上我也写了注释,看应该已经没有什么问题了。
getElementsByClassName的原生实现的更多相关文章
- 原生js方法document.getElementsByClassName在ie8及其以下的兼容性问题
document.getElementsByClassName在ie8及其以下浏览器的兼容性问题,在ie8及其以下浏览器中不能使用,针对这个问题,下面给出详细的解决方法,感兴趣的朋友可以参考下 ...
- js原生封装getClassName()方法-ie不支持getElementsByClassName,所以要自己实现获取类名为className的所有元素
<html> <head> <script type="text/javascript"> window.onload = function() ...
- document.getElementsByClassName() 原生方法 通过className 选择DOM节点
<div id="box"> <div class="box">1</div> <div class="bo ...
- jQuery学习之路(7)- 用原生JavaScript实现jQuery的某些简单功能
▓▓▓▓▓▓ 大致介绍 学习了妙味,用原生的JavaScript实现jQuery中的某些部分功能 定义自己的函数库lQuery ▓▓▓▓▓▓ $()选择器的实现 jQuery是面向对象的,所以自己编写 ...
- 深入理解javascript选择器API系列第二篇——getElementsByClassName
× 目录 [1]使用 [2]classList [3]扩展 前面的话 既然有getElementById()和getElementsByTagName()方法,为什么没有getElementsByCl ...
- 原生JS实现购物车结算功能代码+zepto版
html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3 ...
- 论如何在手机端web前端实现自定义原生控件的样式
手机开发webapp的同学一定遇到过这样问题,如何为丑极了的手机元素应用自定义的样式.首先,要弄清楚为什么要定义手机原生控件的样式,就需要看看手机的那些原生框样式的丑陋摸样: android: ios ...
- JavaScript常见原生DOM操作API总结
[TOC] 最近面试的时候被这个问题给卡了,所以抽时间好好复习一下. 几种对象 Node Node是一个接口,中文叫节点,很多类型的DOM元素都是继承于它,都共享着相同的基本属性和方法.常见的Node ...
- 【前端性能】必须要掌握的原生JS实现JQuery
很多时候,我们经常听见有人说jquery有多快多快.在这个各种类库满天飞的时候,不得不说的是,能有原生JS快吗? 是的,明显原生JS要更快,因为诸如JQuery这样的库必须要兼容各种浏览器和低版本和许 ...
随机推荐
- PyCharm 2018 最新激活方式总结(最新最全最有效)!!!
PyCharm 2018 最新激活方式总结(最新最全最有效!!!) pycharm2018 是目前python编程的主要应用工具,具有非常广泛的应用,不过对于它的破解一直比较麻烦,这里我为大家提供了三 ...
- java学习笔记-8.对象的容纳
1.Iterator(迭代器)和Enumeration(枚举类),都是用来遍历集合的,他们都是接口.区别是Enumeration只能读取集合的数据,而Iterator可以对数据进行删除,Iterato ...
- 春招实习汇总(7个offer)
转载出处 刚从北京到家,总算也可以歇歇了,最近一段时间真是忙于奔命的感觉,也确实体会到了找工作的艰辛,总而言之,求职之路,如人饮水,冷暖自知. 我想把这段时间找工作的体验和经历分享出来告诉大家,让大避 ...
- 你真的了解JAVA里的String么
Java中String类细节问题 (考察点Java内存分配问题) 1. String str1 = "abc"; System.out.println(str1 == &quo ...
- 个人在git配置SSH Key遇到的问题以及解决方案
第一次用git上传代码到github,在这过程中遇到很多问题,在输入git命令的时候都小心翼翼,因为一不小心感觉就会出错.. 英语不好..在敲入git命令过程中各种错误提示勉强翻译下才看得懂 最后输入 ...
- sql查询 同一个字段下另一个字段个数
select seriesid , count(reportid) from reportsystem group by seriesidhaving count(reportid) > 1
- 软件工程课堂作业(三)——Right-BICEP软件单元测试
一.测试方法:Right-BICEP Right-结果是否正确?B-是否所有的边界条件都是正确的?I-能查一下反向关联吗?C-能用其他手段交叉检查一下结果吗?E-你是否可以强制错误条件发生?P-是否满 ...
- iOS-【UIDynamic-UIKit动力学】
如果看不到图片 可以尝试更换浏览器(推荐Safari ) 0.了解 •Dynamic Animator:动画者,为动力学元素提供物理学相关的能力及动画,同时为这些元素提供相关的上下文,是动力学元素与底 ...
- 关于命令行参数argv(《学习OpenCV》)
在<学习OpenCV>这本书中,很多示例代码都用到了命令行参数.作为新手,之前总是很困扰,不知道怎么用.偶然的机会终于略知一二了. 在Visual Studio中,我们可以自行设置命令行参 ...
- pfx 证书怎么打开
其实双击就能够自动运行导入向导的 不行的话使用我的办法: 单击开始--运行--里输入mmc 然后单击文件--选择添加删除管理单元--再选择添加--拉动滚动条找到证书一项,点击添加再点击完成(不用做任何 ...