繁体   English   中英

什么阻止函数被无限调用?

[英]What is preventing function from being called infinitely?

该函数的目的是遍历通过每个子元素上的回调函数的DOM。 如果traverseDom调用自身并重新启动整个函数,那么我将永远不会到达element = element.nextElementSibling。 即使我们最终会击中节点树中的最后一个子节点,我仍认为没有什么阻止该函数无限调用自己,即使在到达最后一个子节点之后也尝试寻找其他子节点。

 function traverseDom(element, callback) { callback(element); element = element.firstElementChild; while (element) { traverseDom(element, callback); element = element.nextElementSibling; } } const subTree = document.getElementById("subTree"); traverseDom(subTree, function(element) { console.assert(element !== null, element.nodeName); }); 
 <div id="subTree"> <form> <input type="text" /> </form> <p>Paragraph</p> <span>Span</span> </div> 

我希望它可以无限运行,并且永远不会到达兄弟元素声明。

在最深层的嵌套元素处, element.firstElementChild将为null ,因此在将其分配给element ,以下条件将不成立:

while(element) {     

...因此根本不进入循环。 此时没有进一步的递归,函数将返回,并且可能发生回溯。 在以前的递归级别执行的函数可能仍会进一步循环,但是最终总会存在不执行该循环的最深层次。 这些代表深度优先遍历树中的叶子。

可变范围

还有另一个方面可能导致混淆:变量element在当前函数执行上下文中是局部的:其值的更改(由于赋值)将不会影响调用函数中具有相同名称的变量。

为了澄清这一点,您还可以重写代码以使用将为其分配子节点的另一个变量名:

 function traverseDom(element, callback) { callback(element); var child = element.firstElementChild; while (child) { traverseDom(child, callback); child = child.nextElementSibling; } } const subTree = document.getElementById("subTree"); traverseDom(subTree, function(element) { console.assert(element !== null, element.nodeName); }); 
 <div id="subTree"> <form> <input type="text" /> </form> <p>Paragraph</p> <span>Span</span> </div> 

该代码将产生相同的结果。 除了不为element分配新值,而是为该新值(第一个子项)使用不同的变量外,它使用相同的逻辑。 但是请注意,当递归调用函数时, child的值将成为parameter-variable element的值。

生成器使您可以更方便地执行此操作-

 function* traverseDom (elem) { yield elem for (const child of elem.children) yield* traverseDom(child) } const subTree = document.getElementById("subTree") for (const elem of traverseDom(subTree)) console.log(elem, elem.nodeName) for (const elem of traverseDom(subTree)) console.assert(elem !== null, elem.nodeName) 
 <div id="subTree"> <form> <input type="text" /> </form> <p>Paragraph</p> <span>Span</span> </div> 

如果您更喜欢高阶函数,那也是可能的-

 function traverseDom (f, elem) { f(elem) for (const child of elem.children) traverseDom(f, child) } const subTree = document.getElementById("subTree") traverseDom ( elem => console.log(elem, elem.nodeName) , subTree ) traverseDom ( elem => console.assert(elem !== null, elem.nodeName) , subTree ) 
 <div id="subTree"> <form> <input type="text" /> </form> <p>Paragraph</p> <span>Span</span> </div> 

暂无
暂无

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

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