原生JS模拟出jquery的find()方法(简单递归)

jQuery中的find()函数可以在给定的父元素中,获得当前父元素下指定的子元素集合。
关于find()的具体使用就不细说了,重点是如何使用原生JS来实现一样的功能。

当时想的方法是用递归来完成DOM树的遍历。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div class="carousel" id="id_carousel">
        <ul class="img-ct">
            <li id="0">
                <a href="#">
                    <p>p0</p>
                </a>
            </li>
            <li id="1">
                <a href="#">
                    <p>p1</p>
                </a>
            </li>
        </ul>
    </div>
    <script>
        function findRecursion(parent, label) {
            for (var i = 0; i < parent.children.length; i++) {
                console.log(parent.children[i]);
                findRecursion(parent.children[i], label);
            }
        }
        /*
        ul.img-ct {compact: false, type: "", title: "", lang: "", translate: true, …}
        li#0 {value: 0, type: "", title: "", lang: "", translate: true, …}
        a {target: "", download: "", ping: "", rel: "", relList: DOMTokenList(0), …}
        p {align: "", title: "", lang: "", translate: true, dir: "", …}
        li#1 {value: 0, type: "", title: "", lang: "", translate: true, …}
        a {target: "", download: "", ping: "", rel: "", relList: DOMTokenList(0), …}
        p {align: "", title: "", lang: "", translate: true, dir: "", …}
        */
    </script>
</body>
</html>

其实自己对递归不是很熟练(科班出身学过算法的优势马上体现出来了有没有!),了解也不是很深刻,以至于当时写出来甚至都不知道如何运行的,后面一步一步打断点运行后才了解,也知道了为什么jQuery中find()的源码没有使用这种方法来遍历DOM。

调试界面

可以看到在调用堆栈中,有5个findRecursion()函数在堆栈内执行,此时遍历DOM深度是遍历到第一个li元素内的p元素上。由于p本身没有后代元素(children.length=0),不会再继续调用函数递归下去,执行栈弹出函数,i自增......直到碰到下一个children.length>1的元素,继续遍历下去。

实际上,节点中每存在一个后代节点,就会执行一次函数,如果元素节点很多很深,很容易造成栈溢出。

        <ul class="img-ct">
            <li id="0">
                <a href="#">
                    <p>p0</p>
                </a>
            </li>
            <li id="1">
                <a href="#">
                    <p>p1</p>
                </a>
            </li>
        </ul>

这是优化了一下函数,简单模拟了find()的功能。加入class、id、tagName参数用于对比,数组用于保存符合功能的元素。

var result = [];
function findRecursion(parent,label) {
    for (var i = 0; i < parent.children.length; i++) {

        if (([].indexOf.call(parent.children[i].classList,label) !== -1) || parent.children[i].id === label || parent.children[i].tagName === label) {
            result.push(parent.children[i]);
        }

        findRecursion(parent.children[i], label);
    }
}

findRecursion(document.querySelectorAll(".carousel")[0],"P");   // Array(4) [p, p, p, p.p3]
console.log(result);
result = [];

findRecursion(document.querySelectorAll(".carousel")[0],"3");   // Array(1) [li#3]
console.log(result);
result = [];

findRecursion(document.querySelectorAll(".carousel")[0],"img-ct");   // Array(1) [ul.img-ct]
console.log(result);
result = [];

测试HTML

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
    <div class="carousel" id="id_carousel">
        <ul class="img-ct">
            <li id="0">
                <a href="#"><p>p0</p></a>
            </li>
            <li id="1">
                <a href="#"><p>p1</p></a>
            </li>
            <li id="2">
                <a href="#"><p>p2</p></a>
            </li>
            <li id="3">
                <a href="#"><p class="p3">p3</p></a>
            </li>
        </ul>
    </div>
</body>
</html>

当然问题也有很多,如没有使用this,参数类型不严谨,每执行一次result数组要归0等等。

关于尾递归


待更

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • jQuery jQuery是JavaScript世界中使用最广泛的一个库。 jQuery这么流行,肯定是因为它解决...
    星腾_范特西阅读 6,283评论 0 27
  • DOM创建节点及节点属性 通过JavaScript可以很方便的获取DOM节点,从而进行一系列的DOM操作。但实际上...
    阿r阿r阅读 4,619评论 0 9
  • 第1章 简介 第2章 DOM节点的创建 2-1 DOM创建节点及节点属性 通过JavaScript可以很方便的获...
    mo默22阅读 4,284评论 0 8
  • 忆往昔峥嵘岁月,看今朝潮起潮落,望未来任重而道远。 Summary As the start-up life in...
    慢慢树阅读 2,707评论 0 0
  • 牛有四个胃,在外时尽可能的吃多的草,回到牛棚后再慢慢反刍,重新咀嚼消化。 最近在准备考试,大一学了的高数,我忘了一...
    1路向前阅读 1,709评论 0 0