两道 JavaScript 题目

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

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

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

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 。

要不来个正则作匹配?

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 方法,而且速度完全不是上面的方法能比拟的,所以在第一种方法的基础上调整一下,判断若是能使用原生方法则使用原生的方法:

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 元素则通过判断并加入结果集,具体代码如下:

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