Javascript DOM树遍历
我最近在Facebook面试了一个前端工程师的职位。对于我的手机屏幕,我有以下问题:给定一个DOM树中的节点,从一个相同的DOM树中找到位于相同位置的节点。请参见下图以了解更多信息Javascript DOM树遍历,javascript,dom,Javascript,Dom,我最近在Facebook面试了一个前端工程师的职位。对于我的手机屏幕,我有以下问题:给定一个DOM树中的节点,从一个相同的DOM树中找到位于相同位置的节点。请参见下图以了解更多信息 A B O O |\ |\ O O O O /|\ /|\ O O O O O O \ \ O O 这是我的解决方案,我想知道我可以做些什么来改进/优化它 var rootA,
A B
O O
|\ |\
O O O O
/|\ /|\
O O O O O O
\ \
O O
这是我的解决方案,我想知道我可以做些什么来改进/优化它
var rootA, rootB;
function findNodeB(nodeA) {
// Variable to store path up the DOM tree
var travelPath = [];
// Method to travel up the DOM tree and store path to exact node
var establishPath = function(travelNode) {
// If we have reached the top level node we want to return
// otherwise we travel up another level on the tree
if (travelNode === rootA) {
return;
} else {
establishPath(travelNode.parentNode);
}
// We store the index of current child in our path
var index = travelNode.parentNode.childNodes.indexOf(travelNode);
travelPath.push(index);
}
var traverseTree = function(bTreeNode, path) {
if(path.length === 0) {
return bTreeNode;
} else {
traverseTree(bTreeNode.childNodes[path.pop()], path);
}
}
establishPath(rootB, nodeA);
return traverseTree(rootB, travelPath);
}
由于至少Axel对迭代解决方案感兴趣,因此: 给定具有相同结构的两棵树,以及第一棵树中的指定节点,在第二棵树中定位该节点,使其在结构中处于相同位置 如果我们没有关于这两棵树的其他信息,那么每个节点的位置可以描述为根节点的路径,其中路径中的每个步骤都被指定为childNode数组的索引
function indexOf(arrLike, target) {
return Array.prototype.indexOf.call(arrLike, target);
}
// Given a node and a tree, extract the nodes path
function getPath(root, target) {
var current = target;
var path = [];
while(current !== root) {
path.unshift(indexOf(current.parentNode.childNodes, current));
current = current.parentNode;
}
return path;
}
// Given a tree and a path, let's locate a node
function locateNodeFromPath(root, path) {
var current = root;
for(var i = 0, len = path.length; i < len; i++) {
current = current.childNodes[path[i]];
}
return current;
}
function getDoppleganger(rootA, rootB, target) {
return locateNodeFromPath(rootB, getPath(rootA, target));
}
函数indexOf(arrLike,target){
返回Array.prototype.indexOf.call(arrLike,target);
}
//给定一个节点和一棵树,提取节点路径
函数getPath(根,目标){
var电流=目标;
var路径=[];
while(当前!==根){
unshift(indexOf(current.parentNode.childNodes,current));
current=current.parentNode;
}
返回路径;
}
//给定一棵树和一条路径,让我们定位一个节点
函数locateNodeFromPath(根,路径){
无功电流=根;
对于(变量i=0,len=path.length;i
编辑:正如蓝天观察到的那样,childNodes没有.indexOf()。使用Array.prototype.indexOf.call()更新我将并行遍历两棵树,当我到达树中的节点时返回并行节点。您可以使用
数组.prototype.indexOf.call
,而不是数组.from
(在ES6中标准化):
Array.from(travelNode.parentNode.childNodes).indexOf(travelNode)代码>这里是并行遍历解决方案
function findDomNodeInTree(rootA, rootB, targetNode) {
if (rootA === targetNode){
return rootB;
}
let nodeB = null;
for (let i=0; i<rootA.childNodes.length && nodeB === null; i++){
nodeB = findDomNodeInTree(rootA.childNodes[i], rootB.childNodes[i], targetNode);
}
return nodeB;
}
函数findDomNodeInTree(rootA、rootB、targetNode){
if(rootA==targetNode){
返回rootB;
}
设nodeB=null;
对于(让i=0;iYou没有得到这份工作?@Mike-我很想看到一种迭代的方法,只是为了比较效率上的差异(以及为了学习的目的)。好吧,看看.childNodes
集合没有indexOf()
method,我想这对你很不利。有趣的是,这也吸引了我。然而,只有当面试官是纳粹分子时,“对你很不利”,在真实场景中,你会很快发现这一点,并使用Array.prototype.indexOf.call()解决另外,为了挑剔,establishPath的签名接受1个参数,但传递2个参数,traverseTree在进行递归调用时需要返回自身(现在,它只进行递归调用,但不返回任何内容)很好,当我们在查看代码时-缓存path.length没有任何意义,因为它是一个数组,而不是节点列表,所以可以访问。length是O(1)两年后,这不应该使用current.parentNode.children
,因为.children
将只返回HTML元素吗?对childNodes
的调用似乎包含@Morklympious不是真正的原因,如果使用children,那么这将不是相同的结构,记住注释是t结构的一部分你不认为这是低效的吗?当你遍历到节点时,你会遇到需要进行不必要检查的分支,这使得算法效率低下(假设你的节点在分支B中,分支A有1000个子/孙辈)。相反,如果从节点遍历到根节点,这将是有效的。好主意。唯一的折衷办法是prototype.index.call直接在对象上运行,而.from().indexOf()则直接在对象上运行将创建一个浅薄的副本,这将增加空间的复杂性。这是一个在采访中很容易解释的权衡。另一个人可以确认这是否是一个正确的解决方案吗?我看不出有任何问题。