这个 javascript 闭包有什么问题?

What is wrong with this javascript closure?

我有一个递归函数 (exploreNode),它更新在其正上方声明的变量 (branch_queue) 的值。 当我 运行 正常时(没有闭包函数),它按预期工作。

当我放置在闭包函数内部时,递归函数没有按照预期的方式遍历子节点。它保持在同一个初始节点上,直到 "Max Call Stack" 错误触发。

递归函数的目的是探索 JSON 树,直到找到所需的 ID。当它遍历树时,branch_queue var 会使用到感兴趣节点的路线图进行更新。

关闭是为了不将 branch_queue 作为全局函数。

我在 es6 和 es5 中都试过了,认为这可能是作用域和使用 "const" 和 "let" 的问题。 示例如下。

我还有下面的代码块,它可以在没有关闭的情况下工作。

我作为参数输入的树

let u = [
  {
    id: 0,
    label: 'l0',
    children: [
      {
        id: 1,
        label: 'l1'
      },
      {
        id: 2,
        label: 'l2',
        children: [
          {
            id: 3,
            label: 'l3'
          },
          {
            id: 4,
            label: 'l4'
          },
          {
            id: 5,
            label: 'l5'
          },
          {
            id: 6,
            label: 'l6',
            children: [
              {
                id: 7,
                label: 'l7'
              },
              {
                id: 8,
                label: 'l8'
              },
              {
                id: 9,
                label: 'l9'
              },
              {
                id: 10,
                label: 'l10'
              }
            ]
          }
        ]
      }
    ]
  }
]

什么起作用了

let branch_queue = [];
// Assumes that the ID exists!
const exploreNode = (nodeIdOfInterest, nodeTree) => {
    // var branch_queue = [];
    for (let i = 0; i < nodeTree.length; i++) {
        const nodeToCheck = nodeTree[i];
        if (nodeToCheck.id == nodeIdOfInterest) {
            branch_queue.push(nodeToCheck.id);
            return nodeToCheck.label;
        } else if(nodeToCheck.children) {
            branch_queue.push(nodeToCheck.id);
            return exploreNode(nodeIdOfInterest, nodeToCheck.children);
        }
    }
}

exploreNode(3, contentTree);
console.log(branch_queue); // prints the correct roadmap

什么不起作用 ES5

function fn (nodeIdOfInterest, nodeTree) {
  let branch_queue = [];
  console.log('here');

  // Assumes that the ID exists!
  function exploreNode () {
      var branch_queue = [];
      console.log('in here');

      for (var i = 0; i < nodeTree.length; i++) {
          var nodeToCheck = nodeTree[i];
          console.log(`${nodeToCheck.label} : ${nodeToCheck.id}`);
          if (nodeToCheck.id == nodeIdOfInterest) {
              console.log('found it');

              branch_queue.push(nodeToCheck.id);
              return nodeToCheck.label;
          } else if(nodeToCheck.children) {
              console.log('checking children');
              branch_queue.push(nodeToCheck.id);
              return exploreNode(nodeIdOfInterest, nodeToCheck.children);
          }
      }
  };

  exploreNode();

  return branch_queue;
}

console.log(fn(3, contentTree)); // throws call stack error

ES6

const fn = (nodeIdOfInterest, nodeTree) => {
  let branch_queue = [];
  console.log('here');

  // Assumes that the ID exists!
  const exploreNode = () => {
      // var branch_queue = [];
      console.log('in here');

      for (let i = 0; i < nodeTree.length; i++) {
          let nodeToCheck = nodeTree[i];
          console.log(`${nodeToCheck.label} : ${nodeToCheck.id}`);
          if (nodeToCheck.id == nodeIdOfInterest) {
              branch_queue.push(nodeToCheck.id);
              return nodeToCheck.label;
          } else if(nodeToCheck.children) {
              branch_queue.push(nodeToCheck.id);
              return exploreNode(nodeIdOfInterest, nodeToCheck.children);
          }
      }
  };

  exploreNode();

  return branch_queue;
};
console.log(fn(3, contentTree)); // throws call stack error

预期输出=> [0 2 3] 实际=>。最大调用堆栈错误

递归函数永远不会超出第一层,并无限期地重复。

nodeTreeexploreNode 的递归版本中始终是相同的起点,即传入 fn 的起点。该版本中对 exploreNode 的每次调用都是全新的:您对 exploreNode 的调用正在传递参数,但它忽略了它们。 "what did work" 版本不会忽略传递给它的参数,所以它可以工作。