简体   繁体   English

javascript中的递归

[英]Recursion in javascript

I am trying to understand how the recursion works. 我试图理解递归是如何工作的。 The code below walks through the nodes of the HTML document. 下面的代码遍历HTML文档的节点。 It invokes a function, passing it each node in turn. 它调用一个函数,依次传递每个节点。 can someone please explain how it is being done in steps? 有人可以解释一下它是如何分阶段完成的吗? thanks. 谢谢。

var walk_the_DOM = function walk(node, func) {
    func(node);
    node = node.firstChild;
    while (node) {
        walk(node, func);
        node = node.nextSibling;
    }
}

The first statement is the function definition: 第一个语句是函数定义:

var walk_the_DOM = function walk(node, func) {
    ...
};

This assigns a function to walk_the_DOM . 这为walk_the_DOM指定了一个函数。 This function takes in two parameters: node , and func . 该函数有两个参数: nodefunc node is the node you want to work on and func is the function you want to apply on node . node是您要处理的节点, func是您要在node上应用的函数。

The first line of the function is func(node); 函数的第一行是func(node); . This essentially means you are applying a passed-in function on node . 这实际上意味着您在node上应用传入函数。 For example, if you called walk_the_DOM like this: 例如,如果您像这样调用walk_the_DOM

walk_the_DOM(root, function(node) {
    console.log(node);
});

You would be calling 你会打电话

function(node) {
    console.log(node);
}

on every node, which as the effect of printing out every node in the tree. 在每个节点上,这是打印出树中每个节点的效果。

The next line node = node.firstChild; 下一行node = node.firstChild; basically reassigns the node to its first child. 基本上将node重新分配给它的第一个子node The reason you need to do this is because you need to look at each child of the current node. 您需要这样做的原因是您需要查看当前节点的每个子节点。 Of course, you also need to look at the children of those children, but we'll get to that part later. 当然,你还需要看看那些孩子的孩子,但我们稍后会谈到那个孩子。

Now we get to the while loop. 现在我们进入while循环。 The condition on this while loop is just while(node) , which just means that the loop will run as long as node is not null or undefined. 这个while循环的条件只是while(node) ,这意味着只要node不是null或未定义,循环就会运行。 In our previous statement we did node = node.firstChild . 在我们之前的声明中,我们做了node = node.firstChild What if the current node has no children? 如果当前节点没有子节点怎么办? Then node.firstChild will be null and so we won't even enter the loop. 然后node.firstChild将为null,因此我们甚至不会进入循环。 We will fall out of it and exit the function ( remember this part; we exit the function if the current node has no children. This is know as the stopping condition of our recursive function ). 我们将退出它并退出函数( 记住这部分;如果当前节点没有子节点,我们退出函数。这被称为我们的递归函数的停止条件 )。

Now inside the while loop, we make our recursive call: walk(node, func); 现在在while循环中,我们进行递归调用: walk(node, func); . Let's ignore what happens here for a second and move onto the next line: node = node.nextSibling; 让我们忽略一下这里发生的事情并转移到下一行: node = node.nextSibling; . Here we're assigning the next sibling of the node back into the variable node . 在这里,我们将节点的下一个兄弟分配回变量node In effect we are iterating over the siblings of this node. 实际上,我们正在遍历此节点的兄弟节点。 Now what if the node has no other sibling (ie, the parent node only has one child)? 现在如果节点没有其他兄弟节点(即父节点只有一个子节点)怎么办? Then node will be null and we will fall out of the loop. 然后node将为null,我们将退出循环。

Now let's get back to the recursive call walk(node, func) . 现在让我们回到递归调用walk(node, func) In the recursive call we call the function itself, which means that the behavior of the function is exactly the same as it was for this iteration. 在递归调用中,我们调用函数本身,这意味着函数的行为与此迭代的行为完全相同。 You might think at this point "But doesn't that mean that this will execute forever?". 你可能会想到这一点“但这不意味着它会永远执行吗?”。 But it won't! 但它不会! Why? 为什么? Remember the stopping condition I mentioned earlier? 还记得我前面提到的停车条件吗? At some point you will pass in a node that has no children which means that the recursive call will exit and come back to the next line ( node = node.nextSibling ) and execution will proceed normally. 在某些时候,您将传入一个没有子节点的节点,这意味着递归调用将退出并返回到下一行( node = node.nextSibling )并且执行将正常进行。 Now if you think of the DOM as a tree (which it is), what this means is that you will travel as far down one branch as you can and once you reach the end, you fall back up one level, and check to see if there are any other siblings. 现在,如果您将DOM视为一棵树(它就是这样),这意味着您将尽可能远离一个分支,一旦到达终点,您就会退回到一个级别,然后检查以查看如果有其他兄弟姐妹。 If there are, you go down that branch as far as you can go. 如果有的话,你可以尽可能地去那个分支。 If not, you fall back up one more level and do the check again. 如果没有,你再回升一级并再次检查。 In this way, you are able to traverse the entire DOM tree. 通过这种方式,您可以遍历整个DOM树。

what this code does is it executes the func function on every element of a subtree. 这段代码的作用是它对子树的每个元素执行func函数。

You pass a node into the walk function. 您将节点传递给walk函数。 it takes all the children of that node, and calls the walk method on them. 它占用该节点的所有子节点,并对它们调用walk方法。

every node can be seen as though it were a sub-tree, and each invocation of the walk function just solves a smaller sub-tree solution. 每个节点都可以看作是一个子树,每次调用walk函数只需要解决一个较小的子树解决方案。 since it just walks it doesn't actually do anything. 因为它只是walks它实际上没有做任何事情。

eventually node.firstChild will be null and since null is compared to false in javascript, it will just not enter the loop. 最终node.firstChild将为null ,因为在javascript中将nullfalse进行比较,它将不会进入循环。

// 1. you define a function
var walk_the_DOM = function walk(node, func) { 

    // 4. you call your callback
    func(node);
    // func.call(node); // inside func, 'this' will be node

    // 5. you get the first child
    node = node.firstChild;

    // 6. as long as 'node' is, so not false, 0, null, undefined or '',
    while (node) {

        // 7. recurse the function, jumps to step 4 (in a new closure of walk)
        walk(node, func);
        // walk_the_DOM(node, func);

        // 8. get the next child, going to step 6
        node = node.nextSibling;
    }

    // 9. no more siblings, current walk returns

}; // 2. the function is defined, by name 'walk' and in var 'walk_the_DOM'!

// 3. you call the function once, with an anonymous callback
walk(document, function (currentNode) { });
// walk_the_DOM(document, function (currentNode) { });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM