technology-blog
technology-blog copied to clipboard
第 4 题:如何遍历一个dom树
function traversal(node) {
//对node的处理
if (node && node.nodeType === 1) {
console.log(node.tagName);
}
var i = 0,
childNodes = node.childNodes,
item;
for (; i < childNodes.length; i++) {
item = childNodes[i];
if (item.nodeType === 1) {
//递归先序遍历子节点
traversal(item);
}
}
}
hello,请问为什么要把i定义在外面?
hello,请问为什么要把i定义在外面?
外面空气好啊
if (item.nodeType === 1) { //递归先序遍历子节点 traversal(item); }
这里的判断可以省略吧,毕竟递归之后又会重新判断
function traversal(node) {
const stack = [];
stack.push(node);
while(stack.length > 0) {
const elem = stack.pop();
if (elem && elem.nodeType === 1) {
console.log(elem.tagName);
const children = elem.children;
const len = children.length;
for (let i = 0; i < len; i++) {
stack.push(children[i]);
}
}
}
}
hello,请问为什么要把i定义在外面?
这样效率高,在那本书上看到过这种写法
hello,请问为什么要把i定义在外面?
这样效率高,在那本书上看到过这种写法
var 的话这个写里面和写外面是一样的把 变量提升 js 没有块级作用域把
//尾递归 function traversal(nodes,deal) { let arr = [] for(let i=0;i<nodes.length;i++){ deal(nodes[i]) if(nodes[i].childNodes){ arr = arr.concat(nodes[i].childNodes) } } if(arr.length){ return traversal(arr,deal) } }
var node,treeWalker = document.createTreeWalker(document.body,NodeFilter.SHOW_ELEMENT)
while(node=treeWalker.nextNode())
console.log(node)
if (item.nodeType === 1) { //递归先序遍历子节点 traversal(item); } 这里的判断可以省略吧,毕竟递归之后又会重新判断
不是元素节点的话没必要往后走了,这个判断还是要的
那是不是应该加一个console.log输出, 是不是就跟上面的console.log输出重复了?
function traversal(node) { const stack = []; stack.push(node); while(stack.length > 0) { const elem = stack.pop(); if (elem && elem.nodeType === 1) { console.log(elem.tagName); const children = elem.children; const len = children.length; for (let i = 0; i < len; i++) { stack.push(children[i]); } } } }
非递归写法,可以的,很强
hello,请问为什么要把i定义在外面?
这样效率高,在那本书上看到过这种写法
var 的话这个写里面和写外面是一样的把 变量提升 js 没有块级作用域把
是的 所以写在外面只是一起定义了变量 更清楚当前作用域定义了哪些变量
// 借用一下前面的
function traversal(node) {
if(!node){
console.log(node);
return;
}
const stack = Array.from(node); // 获取的是 HTMLNodes 类数组对象,转成数组
while(stack.length > 0) {
const elem = stack.pop();
if (elem && elem.nodeType === 1) {
console.log(elem.tagName);
const children = elem.children || [];
children.length>0 && stack.push(...children); // 直接进行解构操作
}
}
}
if (item.nodeType === 1) { //递归先序遍历子节点 traversal(item); }
这里的判断可以省略吧,毕竟递归之后又会重新判断
不满足条件就直接不后续处理了呗,省略条件 traversal 又会执行一遍(根本没什么意义)
// 借用一下前面的 function traversal(node) { if(!node){ console.log(node); return; } const stack = Array.from(node); // 获取的是 HTMLNodes 类数组对象,转成数组 while(stack.length > 0) { const elem = stack.pop(); if (elem && elem.nodeType === 1) { console.log(elem.tagName); const children = elem.children || []; children.length>0 && stack.push(...children); // 直接进行解构操作 } } }
const stack =[...node]; 更喜欢这样,哈哈 非递归写法,很下饭啊
function traversal(node) { const stack = []; stack.push(node); while(stack.length > 0) { const elem = stack.pop(); if (elem && elem.nodeType === 1) { console.log(elem.tagName); const children = elem.children; const len = children.length; for (let i = 0; i < len; i++) { stack.push(children[i]); } } } }
不是 queue ?
function traversal(node) {
let stack = [node];
while(stack.length > 0){
const curNode = stack.pop();
if (curNode) {
if (curNode.nodeType === 1) {
console.log(curNode.tagName);
}
const childNodes = [...curNode.childNodes];
stack = stack.concat(childNodes);
}
}
}
https://developer.mozilla.org/zh-CN/docs/Web/API/NodeIterator
为什么不使用这个
function bfsDom(node) {
if(!node) return;
let queue = [];
queue.push(node);
let i = 0;
while(i < queue.length) {
queue = [...queue, ...queue[i].childNodes];
i++;
}
return queue;
}