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的原生实现的更多相关文章

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

    document.getElementsByClassName在ie8及其以下浏览器的兼容性问题,在ie8及其以下浏览器中不能使用,针对这个问题,下面给出详细的解决方法,感兴趣的朋友可以参考下     ...

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

    <html> <head> <script type="text/javascript"> window.onload = function() ...

  3. document.getElementsByClassName() 原生方法 通过className 选择DOM节点

    <div id="box"> <div class="box">1</div> <div class="bo ...

  4. jQuery学习之路(7)- 用原生JavaScript实现jQuery的某些简单功能

    ▓▓▓▓▓▓ 大致介绍 学习了妙味,用原生的JavaScript实现jQuery中的某些部分功能 定义自己的函数库lQuery ▓▓▓▓▓▓ $()选择器的实现 jQuery是面向对象的,所以自己编写 ...

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

    × 目录 [1]使用 [2]classList [3]扩展 前面的话 既然有getElementById()和getElementsByTagName()方法,为什么没有getElementsByCl ...

  6. 原生JS实现购物车结算功能代码+zepto版

    html <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3 ...

  7. 论如何在手机端web前端实现自定义原生控件的样式

    手机开发webapp的同学一定遇到过这样问题,如何为丑极了的手机元素应用自定义的样式.首先,要弄清楚为什么要定义手机原生控件的样式,就需要看看手机的那些原生框样式的丑陋摸样: android: ios ...

  8. JavaScript常见原生DOM操作API总结

    [TOC] 最近面试的时候被这个问题给卡了,所以抽时间好好复习一下. 几种对象 Node Node是一个接口,中文叫节点,很多类型的DOM元素都是继承于它,都共享着相同的基本属性和方法.常见的Node ...

  9. 【前端性能】必须要掌握的原生JS实现JQuery

    很多时候,我们经常听见有人说jquery有多快多快.在这个各种类库满天飞的时候,不得不说的是,能有原生JS快吗? 是的,明显原生JS要更快,因为诸如JQuery这样的库必须要兼容各种浏览器和低版本和许 ...

随机推荐

  1. 记录---Testin上新手测试用例设计实战---碎乐3.2.0

    平台上给的版本是碎乐3.12版的,但是平台上给的安装包下载不了,所以加群咨询之后给出了直接去手机应用商店下载搜索到的版本的对策.所以就那应用商店中找到的3.2.0版本来设计测试用例.因为任务中没有给出 ...

  2. Selenium 入门到精通系列:五

    Selenium 入门到精通系列 PS:显式等待.隐式等待.强制等待方法 例子 #!/usr/bin/env python # -*- coding: utf-8 -*- # @Date : 2019 ...

  3. Ubuntu—安装并运行sublime

    step1 到官网看看 https://www.sublimetext.com/3 step2 根据版本选择,我的是32位的 step3 ubuntu终端安装 (1)切换目录 -$ cd /opt  ...

  4. IMX6移植htop

    top命令查看CPU利用率并不是很方便,因此打算移植htop到imx6上,主要包括以下几个步骤: - 资源下载 htop 下载http://hisham.hm/htop/releases/1.0.1/ ...

  5. 一些容易记混的c++相关知识点

    一些容易记混的c++相关知识. 截图自:<王道程序员面试宝典>

  6. mysql数据库配置主从同步

    MySQL主从同步的作用 .可以作为一种备份机制,相当于热备份 .可以用来做读写分离,均衡数据库负载 MySQL主从同步的步骤 一.准备操作 .主从数据库版本一致,建议版本5.5以上 .主从数据库数据 ...

  7. js随机数算法

    function rnd( seed ){ seed = ( seed * 9301 + 49297 ) % 233280; //为何使用这三个数? return seed / ( 233280.0 ...

  8. 关于LNMP常见问题和性能方面的个人理解

    简单整理,自己做备忘的,不为其他作任何参考- PHP程序 1.开启慢日志,过滤超时时间为1s的方法,针对性优化,可以通过添加缓存方式解决. 2.过滤access日志,统计哪些请求较多较为频繁,是否合理 ...

  9. 【数位DP】题集

    1.[HDOJ2089] 题意:求区间内不出现4和62的数的个数 解法:模板题 2.[HDOJ3555] 题意:求区间内不出现49的数的个数 解法:模板题 3.[HDOJ5179] 题意:对于一个十进 ...

  10. block知识总结

    一.block在内存中存在的形式 1.当把block句法写在函数或者方法外面时,系统会在静态数据区分配一块内存区域给block对象.这片区域在程序执行期会一直存在. 2.当block句法写在函数或者方 ...