zoukankan      html  css  js  c++  java
  • getElementsByClassName实现

    先来看一下代码:(支持多个class查询和在某个范围内进行查询)

    01 /*
    02  * 根据元素clsssName得到元素集合
    03  * @param fatherId 父元素的ID,默认为document
    04  * @tagName 子元素的标签名
    05  * @className 用空格分开的className字符串
    06  */
    07 function getElementsByClassName(fatherId,tagName,className){
    08     var node = fatherId&&document.getElementById(fatherId) || document;
    09     tagName = tagName || "*";
    10     className = className.split(" ");
    11     var classNameLength = className.length;
    12     for(var i=0,j=classNameLength;i<j;i++){
    13         //创建匹配类名的正则
    14         className[i]= new RegExp("(^|\\s)" + className[i].replace(/\-/g, "\\-") + "(\\s|$)");
    15     }
    16     var elements = node.getElementsByTagName(tagName);
    17     var result = [];
    18     for(var i=0,j=elements.length,k=0;i<j;i++){//缓存length属性
    19         var element = elements[i];
    20         while(className[k++].test(element.className)){//优化循环
    21             if(k === classNameLength){
    22                 result[result.length] = element;
    23                 break;
    24             }  
    25         }
    26         k = 0;
    27     }
    28     return result;
    29 }

    好,我们来测试一下:

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

    正确的得到了结果。

     

    关于class属性

    1.一个元素可以带有多个class属性值,它们通过空格分隔, 例:class='aa bb cc'。

    2.class属性值是可以包含'-'这个字符的,如:class='a-b',特别强调是因为在正则表达式中'-'是一个特殊字符。

    3.在javascript中通过的获取class属性值的方式为element.className。

     

    原生的getElementsByClassName

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

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

    所以,这里舍弃了原生的方法调用。

     

    关于循环优化的问题

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

     

     

    额外的收获

     这是关于往数组里放元素的方式间,效率比较的问题

    来看一下代码:

    01 //方式一
    02 var arr = [];
    03 var start = new Date();
    04 for(var i=0;i<100000;i++){
    05     arr.push(i);
    06 }
    07  
    08 //方式二
    09 var arr = [];
    10 var start = new Date();
    11 for(var i=0;i<100000;i++){
    12     arr[arr.length]=i;
    13 }

    猜猜看,哪种效率更高呢!经过测试,第二种方式的效率要高于第一种。

     

    提醒:

    这个版本是不兼容IE5的,以下是我给出的解释:

    1.当你从那千分之几的统计数据里,再去疯钱的IE5测试人员的点击和专业程序员对IE5的好奇心,估计就只剩IE5被焚烧后的灰烬了。

    2.你要想信灰烬的利用价值趋于零

    3.如果到现在还没能说服你,那我想说,你很专业!即然这样,那还有IE3,IE2,IE?FF1,NN4...,我想你应该一并实现了。

     

    一些坦白:我也不怎么说服得了我自已,唉,还是给一个IE5的解决方案吧:

     IE5并不支持getElementByTagName("*")的形式,所以在这里要处理一下:

    var elements = (tagName==='*'&&node.all)?node.all:node.getElementsByTagName(tagName);

    好了,不多说的,这个函数简单实用,代码上我也写了注释,看明白应该已经没有什么问题了

  • 相关阅读:
    zookeeper分布式锁和服务优化配置
    【转】从Mac/OS和iOS开放源码浅谈UNIX家谱
    【转】深入了解CPU两大架构ARM与X86
    【转】volatile关键字。编译器不优化,多线程会改。防止随时变动的
    栈,寄存器,局部变量,内存,语言级别优化程序的方法
    在coursera上有哪些值得推荐的课程
    【转】楼天城楼教主的acm心路历程(作为励志用)
    硬中断软中断
    CPU GPU FPU TPU 及厂商
    C#中使用DLL相关问题
  • 原文地址:https://www.cnblogs.com/aaronjs/p/2167530.html
Copyright © 2011-2022 走看看