如何在javascript中的迭代器生成器中实现递归遍历?

假设我在
javascript中有一棵树,如下所示:

let rootNode = {name:'', children:[
                   {name:'0', children:[
                       {name:'00', children:[]},
                       {name:'01', children:[
                           {name:'010', children:[]},
                       ]},
                       {name:'02', children:[]},
                   ]},
                   {name:'1', children:[
                       {name:'10', children:[]},
                   ]},
               ]};

我想对它进行前序遍历,我可以这样做:

function preOrderTraversalRecursive(rootNode, visitNodeCallback) {
    function recurse(node) {
        visitNodeCallback(node);
        for (let childNode of node.children)
          recurse(childNode);
    }
    recurse(rootNode);
};
console.log("Pre-order traveral, recursive:");
preOrderTraversalRecursive(rootNode, function visitNodeCallback(node) {
    console.log("  '"+node.name+"'");
});

它给出了预期的输出:

  Pre-order traveral, recursive:
    ''
    '0'
    '00'
    '01'
    '010'
    '02'
    '1'
    '10'

现在让我们说我想做同样的事情ES6发电机式.我以为这会是这样的:

function *preOrderGeneratorIteratorRecursive(rootNode) {
    function recurse(node) {
        yield node;
        for (let childNode of node.children)
            recurse(childNode);
    }
    recurse(rootNode);
};
console.log("Pre-order generator iterator, recursive:");
for (let node of preOrderGeneratorIteratorRecursive(rootNode)) {
    console.log("  '"+node.name+"'");
}

但显然这是非法的:Uncaught SyntaxError:在yield时出现意外的严格模式保留字.

令人失望!我缺少一些语法吗?
制作表达此算法的生成器的最简洁方法是什么?
也许使用一些帮助库?

我知道我可以使用如下的显式堆栈,但由于以下几个原因,这并不令人满意:
(1)逻辑被模糊到没有的地步
使用发电机的可读性优势;不妨回去吧
到递归回调版本,和
(2)它不是真正相同的算法,因为它是向后迭代的
在每个node.children上.特别是,这意味着它不起作用
如果node.children是其他类型的可迭代的,可能来自另一个生成器.

function *preOrderTraversalIteratorGeneratorExplicitStackCheating(rootNode) {
  let stack = [rootNode];
  while (stack.length > 0) {
    let node = stack.pop();
    yield node;
    for (let i = node.children.length-1; i >= 0; --i) // backwards
      stack.push(node.children[i]);
  }
} // preOrderIteratorGeneratorExplicitStackCheating
console.log("Pre-order traveral of tree with explicit stack, cheating:");
for (let node of preOrderTraversalIteratorGeneratorExplicitStackCheating(rootNode)) {
  console.log("  '"+node.name+"'");
}

要明确:我对隐藏可怕细节的特殊帮助者不感兴趣
显式堆栈遍历实现.
我想知道是否有一种方法可以清楚地编写迭代器生成器算法,即使它们恰好是递归的.

最佳答案 这确实是为yield *运算符提供的.从本质上讲,您需要将此视为一个将其功能委托给另一个的生成器. (实际上,您可以委托任何可迭代的值.)

例如,您可以这样做:

function *pointlessGenerator() {
    yield* [1, 2, 3, 4];
} 

这将产生1,2,3和4,因为yield *运行迭代器并依次产生所有迭代器的值.如果传递生成器,则会发生完全相同的行为.

在你的情况下,你想要递归一个生成器然后用yield *调用它:

function *preOrderGeneratorIteratorRecursive(rootNode) {
    function *recurse(node) {
        yield node;
        for (let childNode of node.children)
            yield* recurse(childNode);
    }
    yield* recurse(rootNode);
};
console.log("Pre-order generator iterator, recursive:");
for (let node of preOrderGeneratorIteratorRecursive(rootNode)) {
    console.log("  '"+node.name+"'");
}
点赞