Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/391.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript DOM树遍历_Javascript_Dom - Fatal编程技术网

Javascript 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,

我最近在Facebook面试了一个前端工程师的职位。对于我的手机屏幕,我有以下问题:给定一个DOM树中的节点,从一个相同的DOM树中找到位于相同位置的节点。请参见下图以了解更多信息

 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()则直接在对象上运行将创建一个浅薄的副本,这将增加空间的复杂性。这是一个在采访中很容易解释的权衡。另一个人可以确认这是否是一个正确的解决方案吗?我看不出有任何问题。