递归函数没有被执行

Recursive function is not being executed

我正在尝试从 JSON 文件递归加载场景图结构。 我的想法是在所有子节点上调用相同的函数,直到最后一个节点没有子节点为止。但是,在调试代码时,我发现在第二个循环中对 loadNodes 的递归调用被忽略了,而是循环只是增加计数器并从下一个循环开始。

我检查了我的语法并检查了在循环内调用其他函数(有效)..

有人知道我做错了什么吗?

function loadNodes(obj, current_group_node) {
    for (let i = 0; i < obj.length; i++) {
        if (obj[i].nodetype === 'group') {
            let new_group_node = new GroupNode(new Matrix(obj[i].matrix));
            current_group_node.add(new_group_node);
            for (let j = 0; j < obj[i].children.length; j++) {
                loadNodes(obj[i].children[j], new_group_node);
            }
        } else {
           // some more logic

        }
    }
}

我的函数接收具有以下可能结构的对象数组:

{
  "nodetype": "group",
  "name": "root",
  "matrix": [
    1,0,0,0,
    0,1,0,0,
    0,0,1,0,
    0,0,0,1
  ],
  "children": [
    {
      "nodetype": "group",
      "name": "driver-cube-group",
      "matrix": [
        1,0,0,0,
        0,1,0,0,
        0,0,1,0,
        0,0,0,1
      ],
      "children": [
        {
          "nodetype": "aabox",
          "name": "driver-cube",
          "minpoint": {
            "x": -3,
            "y": -3,
            "z": -3,
            "w": 1
          },
          "maxpoint": {
            "x": -2,
            "y": -2,
            "z": -2,
            "w": 1
          },
          "color": {
            "x": 1,
            "y": 1,
            "z": 1,
            "w": 1
          }
        }
      ]
    }
  ]
}

loadNodes 期望第一个参数是对象数组,而不是单个对象。您不需要在每个子对象上循环调用它,只需调用一次,将 child 数组作为参数传递。它自己对数组进行循环。

所以替换这个:

        for (let j = 0; j < obj[i].children.length; j++) {
            loadNodes(obj[i].children[j], new_group_node);
        }

与:

        loadNodes(obj[i].children, new_group_node);

将第一个参数从 obj 重命名为 arr 可能会有所帮助,以明确它需要一个数组,而不是单个对象。

如果将 JSON 传递给您发布的函数,我想出了以下解决方案(我更改了一些术语和还通过创建一个对象并为嵌套对象分配一个数组来替换两个实例化):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xml:lang="en">
<head>
<title>JSON Test Case</title>
<script type="application/javascript">
/* <![CDATA[ */
'use strict';

var nested = 0;

function loadNodes(p_obj, p_current_group_node)
  {
let l_i;
let l_new_group_node;

  nested++;

  console.log('Entering loadNodes (' + nested + ')...');
  console.log('Length of object: ' + p_obj.length);     // Oops...!
  console.log('Type of JSON object: ' + typeof p_obj);
  console.log('Determining the node type: ' + p_obj.nodetype);
  console.log('Node name: ' + p_obj.name);
  if(p_obj.nodetype == 'group')
    {
    console.log('Number of elements: ' + p_obj.children.length);

    for(l_i = 0; l_i < p_obj.children.length; l_i++)
      {
      console.log('Found a subtree for processing!');

      l_new_group_node = new Object();
      l_new_group_node.nodes = new Array();
      p_current_group_node.nodes.push(l_new_group_node);
      loadNodes(p_obj.children[l_i], l_new_group_node);
      }
    }
  else
    console.log('Process leaf node here...');

  console.log('Leaving loadNodes (' + nested + ')...');
  nested--;
  }
/* ]]> */
</script>
</head>
<body>
<header><h1>JSON test case</h1></header>
<main>
<script type="application/javascript">
/* <![CDATA[ */
var json = {
  "nodetype": "group",
  "name": "root",
  "matrix": [
    1,0,0,0,
    0,1,0,0,
    0,0,1,0,
    0,0,0,1
  ],
  "children": [
    {
      "nodetype": "group",
      "name": "driver-cube-group",
      "matrix": [
        1,0,0,0,
        0,1,0,0,
        0,0,1,0,
        0,0,0,1
      ],
      "children": [
        {
          "nodetype": "aabox",
          "name": "driver-cube",
          "minpoint": {
            "x": -3,
            "y": -3,
            "z": -3,
            "w": 1
          },
          "maxpoint": {
            "x": -2,
            "y": -2,
            "z": -2,
            "w": 1
          },
          "color": {
            "x": 1,
            "y": 1,
            "z": 1,
            "w": 1
          }
        }
      ]
    }
  ]
}
var myobj = new Object();
myobj.nodes = new Array();

loadNodes(json, myobj);
/* ]]> */
</script>
</main>
</body>
</html>

首先,我可以抛出外循环,因为它甚至不会启动,因此会阻止递归(我发现 p_obj.length 甚至 returns undefined 如果您正在尝试访问此 属性)。毕竟,它是一个对象,显然不提供长度。相反,我正在检查我们收到的对象的参数,然后确定我们是否需要进一步下降或实际上已经到达叶节点。

如果我们需要进一步下降,有一个有效的循环来挖掘分配给 属性 children 的数组——它实际上有一个长度,所以我们可以把它作为我们的终止条件。

如果您想查看实际发生的情况,可以 运行 在打开浏览器控制台的情况下查看此测试用例。我插入了各种记录特定信息的语句,这样您就可以看到这里发生了什么。
您还应该注意条目 Entering loadNodes (...)Leaving loadNodes (...),因为它们告诉您递归的位置实际上正在发生并且递归调用的函数被保留时。您可以在括号中找到嵌套级别。