前言
如果要对 DOM 树或者其他树形结构的数据进行遍历,可以有两种方式。一种是深度优先遍历,另一种是广度优先遍历。
DOM 树结构
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div class="parent">
<div class="child-1">
<div class="child-1-1">
<div class="child-1-1-1">a</div>
</div>
<div class="child-1-2">
<div class="child-1-2-1">b</div>
</div>
<div class="child-1-3">
c
</div>
</div>
<div class="child-2">
<div class="child-2-1">
d
</div>
<div class="child-2-2">
<div class="child-2-2-1">测试</div>
e
</div>
</div>
<div class="child-3">
<div class="child-3-1">
f
</div>
<div class="child-3-2">
g
</div>
</div>
</div>
</body>
</html>
深度优先遍历
深度优先遍历:也就是纵向遍历。遍历完父节点之后,开始遍历第一个子节点,第一个字节点下面的所有子节点,再遍历第二个子节点,第二个子节点下面的所有子节点。以此类推,总之就是先纵向,再横向。比如,如果我想学习 JavaScript、Java、C++。我会先把 JavaScript 学透,从语法到运用到底层实现都精通之后,再去学 Java,也是先把 Java 研究透。最后再去学 C++。
let deepTraversal = (node, nodeList = []) => {
if (node !== null) {
nodeList.push(node);
let children = node.children;
for (let i = 0; i < children.length; i++) {
deepTraversal(children[i], nodeList)
}
}
return nodeList
};
console.log(deepTraversal (document.getElementsByClassName("parent")[0]));
广度优先遍历
广度优先遍历:也就是横向遍历。遍历
完父节点之后,开始遍历第一个子节点,第二个子节点,第三个子节点,,,直到把父元素下面的子节点都遍历完成之后。再开始遍历第一个元素下面的子节点,第二个元素下面的子节点,第三个元素下面的子节点,以此类推,直到遍历完所有元素。比如,如果我想学习 JavaScript、Java、C++。我会先学习 JavaScript 语法,再学习 Java 语法,再学习 C++ 语法。横向地学完这些语法之后,再去学习 JavaScript 运用(写项目),Java 运用(写项目), C++ 运用(写项目),以此类推。横向地学习完所有语言。
let widthTraversal = function (node,nodeList = [],stack = []) {
if(node){
stack.push(node);
while(stack.length){
var item = stack.shift();
nodeList.push(item);
let child = item.children;
for(let i=0;i<child.length;i++){
stack.push(child[i]);
};
}
}
return nodeList
}
console.log(widthTraversal(document.getElementsByClassName("parent")[0]));
总结
- 深度优先遍历,实现原理是:
(1)将当前 Node 节点 push 到数组;
(2)轮询当前节点的子节点,将每一个子节点作为 当前节点重复(1)步骤(进行递归)。 - 广度优先遍历,实现原理是:
(1)将父元素(rootNode) push 到栈(stack)之后;
(2)只要栈中还有数据,删除栈的第一个元素(rootNode),同时 push 到累计数组中(nodeList)
(3)获取其子元素(rootNode.children) 也 push 到栈(stack)中;
(4)重复(2)(3)步骤。