【问题标题】:What is wrong with this javascript closure?这个 javascript 闭包有什么问题?
【发布时间】:2019-08-02 21:41:23
【问题描述】:

我有一个递归函数 (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] 实际 => 。最大调用堆栈错误

递归函数永远不会超出第一级,并且会无限重复。

【问题讨论】:

    标签: javascript recursion closures stack-trace


    【解决方案1】:

    nodeTree 在递归版本的exploreNode 中始终是相同的起点,即传递给fn 的起点。在该版本中对exploreNode 的每次调用都是从新开始的:您对exploreNode 的调用正在传递参数,但它忽略了它们。 “做了什么”版本没有忽略传递给它的参数,所以它可以工作。

    【讨论】:

    • 如果这不是我犯过的最愚蠢的错误。
    • 非常感谢@T.J Crowder。感谢您的快速回复!
    猜你喜欢
    • 2015-01-14
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多