简体   繁体   English

递归函数没有被执行

[英]Recursive function is not being executed

I am trying to recursively load a scenegraph structure from a JSON file.我正在尝试从 JSON 文件递归加载场景图结构。 My idea was to call the same function on all child nodes until the last node has no children.我的想法是在所有子节点上调用相同的函数,直到最后一个节点没有子节点。 However when debugging the code I found that the recursive call of loadNodes inside the second loop is being ignored and instead the loop just increases the counter and starts with the next loop.但是,在调试代码时,我发现第二个循环中 loadNodes 的递归调用被忽略,而循环只是增加计数器并从下一个循环开始。

I checked my syntax and I check calling other functions inside the loop (which works)..我检查了我的语法,并检查了在循环内调用其他函数(有效)。

Does anybody have an idea on what I am doing wrong?有人知道我做错了什么吗?

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

        }
    }
}

My function receives an array of objects with the following possible structure:我的函数接收具有以下可能结构的对象数组:

{
  "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 expects the first argument to be an array of objects, not a single object. loadNodes期望第一个参数是一个对象数组,而不是单个对象。 You don't need to call it in a loop on each child object, just call it once, passing the child array as the argument.您不需要在每个子对象的循环中调用它,只需调用一次,将child数组作为参数传递。 It does its own looping over the array.它对数组进行自己的循环。

So replace this:所以替换这个:

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

with:和:

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

It might be helpful to rename the first argument from obj to arr , to make it clear that it expects an array, not a single object.将第一个参数从obj重命名为arr可能会有所帮助,以明确它需要一个数组,而不是单个对象。

Providing the JSON is passed to your function as you have posted it , I have come up with the following solution (I have changed some of the nomenclature and also replaced two instantiations by creating an object and assigning an array to it for nested objects):提供 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>

First of all, I could toss out the outer loop, because that doesn't even fire up and so prevents the recursion (I have found that p_obj.length even returns undefined if you are trying to access this property).首先,我可以抛弃外部循环,因为它甚至不会启动,因此可以防止递归(我发现如果您尝试访问此属性, p_obj.length甚至返回undefined )。 After all, it's an object, and that obviously doesn't provide a length.毕竟,它是一个对象,显然不提供长度。 Instead I am checking the parameters of the object that we have received and then determine if we need to descend any further or have actually reached a leaf node.相反,我正在检查我们收到的对象的参数,然后确定我们是否需要进一步下降或实际到达叶节点。

If we need to descend any further, there's a loop in effect to dig through the array assigned to the property children - that actually has a length so we can take that for our termination condition.如果我们需要进一步下降,实际上有一个循环来挖掘分配给属性children的数组 - 它实际上有一个长度,因此我们可以将其作为终止条件。

If you want to see what's actually happening, you can run this test case with your browser's console open.如果您想查看实际发生的情况,可以在浏览器控制台打开的情况下运行此测试用例。 I have inserted various statements that log particular information to it so you can see what's being done here.我已经插入了各种记录特定信息的语句,以便您可以看到这里做了什么。
You should also pay attention to the entries Entering loadNodes (...) and Leaving loadNodes (...) , because they tell you where recursion is actually taking place and when the recursively invoked function is left.您还应该注意Entering loadNodes (...)Leaving loadNodes (...)条目,因为它们会告诉您递归实际发生的位置以及递归调用的函数何时离开。 You can find the nesting level in the parentheseses.您可以在括号中找到嵌套级别。

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

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