两道 JavaScript 题目

偶遇两道 JavaScript 题目,觉得都比较有趣,分享一下。

第一道是很老的题目了,getElementsByClassName,写一下当作练习:

下面这个思路比较简单,基本也是 Robert Nyman 的思路了,判断了 IE5 中使用原生的 all 属性代替其不支持的 getElementsByTagName ,使用 indexOf 判断相应的 class 是否匹配。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function getElementsByClassName(className, context, tag){
 
    context = context || document;
 
    tag = tag || '*';
 
    var el = ( tag === '*' && context.all) ? context.all : context.getElementsByTagName(tag); // 兼容 IE5
 
    var resultElements = [];
 
    var oElement;
 
    for( var i = 0; i < el.length; i++ ){
        oElement = el[i];
        if( oElement.className.indexOf(className) != -1 ) resultElements.push(oElement);
    }
 
    return resultElements;
 
}

在 Chrome 下,匹配 10003 个 class 为 "c" 的 div ,历时 5-8 ms ,IE 7 下历时 40-47 ms 。

要不来个正则作匹配?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function getElementsByClassName(className, context, tag){
 
    context = context || document;
 
    tag = tag || '*';
 
    var el = ( tag === '*' && context.all) ? context.all : context.getElementsByTagName(tag);
 
    var resultElements = [];
 
    className = className.replace(/\-/g, "\\-"); // 转义 className
 
    var oRegExp = new RegExp('(^|\\s)' + className + '(\\s|$)');
 
    var oElement;
 
    for( var i = 0; i < el.length; i++ ){
        oElement = el[i];
        if( oRegExp.test(oElement.className) ){
            resultElements.push(oElement);
        }
 
    }
 
    return resultElements;
 
}

原理跟上面是一样的,但是匹配 class 部分改为用正则表达式,同样是匹配 10003 个 class 为 "c" 的 div ,在 Chrome 下历时 6-9 ms ,在 IE 7 下历时 46-50 ms 。看来,高端的正则在这里并不如期待那样奏效,还是选用第一种方法吧。

不过,Chrome , Firefox 等现代浏览器都有原生的 getElementsByClassName 方法,而且速度完全不是上面的方法能比拟的,所以在第一种方法的基础上调整一下,判断若是能使用原生方法则使用原生的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function getElementsByClassName(className, context, tag){
 
    if( document.getElementsByClassName ){
 
        return document.getElementsByClassName(className);
 
    } else {   
 
        context = context || document;
 
        tag = tag || '*';
 
        var el = ( tag === '*' && context.all) ? context.all : context.getElementsByTagName(tag);
 
        var resultElements = [];
 
        var oElement;
 
        for( var i = 0; i < el.length; i++ ){
            oElement = el[i];
            if( oElement.className.indexOf(className) != -1 ){
                resultElements.push(oElement);
            }
 
        }
 
        return resultElements;
 
    }
 
}

仍是匹配 10003 个 class 为 "c" 的 div ,在 Chrome 下历时 1 ms ,在 IE 下由于 IE 并不支持原生方法,所以仍是 40-47 ms 。另外测试了匹配 50003 个 class 为 "c" 的 div ,在 Chrome 下只需 3 ms (原生方法就是霸气)。

第二道题目是网上看到的淘宝的一道面试题,从 #id 元素内选出所有不是 .c 后代的 a 元素。思路是找到所有 a 元素,逐层遍历其父级元素,判断其 class 是否包含 c ,若有包含则中止本次判断,否则遍历至 #id 元素则通过判断并加入结果集,具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function getElementNotInClass(tag, filterClass, context){
 
    var context = document.getElementById(context) || document.body,
        nodes = context.getElementsByTagName(tag),
        resultElements = [],
        current,
        i;
  
    again: for(i = 0, l = nodes.length; i < l; i++){
 
        current = nodes[i].parentNode;
 
        while( current != context ){
            if( current.className.indexOf(filterClass) == -1 ) current = current.parentNode;
            else continue again;
        }
        resultElements.push(nodes[i]);
    }
  
    return resultElements;
}

本文由 Kayo Lee 发表,本文链接:https://kayosite.com/two-javascript-subjects.html

评论列表

  • 评论者头像
    回复

    第二题没看懂路过~

    • 评论者头像
      回复

      @ilikecss 第二题我的思路是把所有的标签放到集合里,再逐个递归其父结点判断类名是否有指定的c类名

  • 评论者头像
    回复

    个人感觉第一道题的解法应该有点问题,比如说要查询的 taba.a,但是 taba下有两种 .a 和 .ab,似乎 indexOf 就会有问题~感觉把 class 属性的内容 split 之后循环比对可能会更好点,或者说用正则?

    • 评论者头像
      回复

      @MurphyL 嗯,同意你的意见,不过 split 之后再循环效率会比较低,可以在 用 indexOf 判断时判断两边是否有空格,待会更新一下文章再一起研究!

      • 评论者头像
        回复

        @Kayo split 应该还好,感觉应该可以在indexOf的className之后拼上一个空格。

  • 评论者头像
    回复

    端午节了 快更新 快更新吧

    • 评论者头像
      回复

      @刘荣焕 最近在学习新的东东,过几天有点心得了就会发文章了,习惯了有心得才写博客,所以只能慢慢来了

  • 评论者头像
    回复

    我是不会做了。。。坐下休息片刻

  • 评论者头像
    回复

    🙁 我是来打酱油的~

  • 评论者头像
    回复

    Kayo!!好久沒來了,還是看不懂XD

    最近好嗎好嗎?這次下定決心一週至少要更新一次,希望能達成目標 :mrgreen:

    • 评论者头像
      回复

      @班森 最近乃是各种忙啊,博客都长草了,一个月都没有更新了!

  • 评论者头像
    回复

    看了好有深度的,还是来学习一下

  • 评论者头像
    回复

    ie8 以上支持 Document.querySelectorAll, 这个速度很快

  • 评论者头像
    回复

    这么久了,不知博主还在否
    第二题我的思路是找两集合,一是所有a all,二是.c下所有a ca
    然后遍历all,判断元素是否在ca集合中,如果不在ca中,就是题目所要求的a。

回复

你正在以游客身份访问网站,请输入你的昵称和 E-mail