【问题标题】:JavaScript recursion odd behaviour?JavaScript递归奇怪的行为?
【发布时间】:2016-11-07 18:47:00
【问题描述】:

我无法理解为什么我用 JavaScript 编写的递归函数会出现问题。当我给它提供一个大的 json 文件时,它会陷入无限循环。我觉得这与 JavaScript 闭包的工作方式有关。跳个聪明的可以看看我的代码并解释发生了什么。

我已将 line 的函数 line 移植到 PHP,它会产生我期望的输出。

JavaScript:

var jsonfile = process.argv[2];

json = require("./"+jsonfile);

path = "2";

buildPaths(json, path);

function buildPaths(json, path) {

    if (json.Children == null || json.Children.length == 0) {

        console.log(path + "/" + json.TypedItemId);

    } else {

        for (i = 0; i < json.Children.length; i++) {
            buildPaths(json.Children[i], path + "/" + json.TypedItemId);
        }
    }

}

移植到 PHP:

<?php
$jsonfile = $argv[1];
$json = json_decode(file_get_contents($jsonfile));

$path = "2";

buildPaths($json, $path);

function buildPaths($json, $path) {


    if ($json->Children == null || count($json->Children) == 0) {

        echo $path . "/" . $json->TypedItemId . "\n";

    } else {

        for ($i = 0; $i < count($json->Children); $i++) {
            buildPaths($json->Children[$i], $path . "/" . $json->TypedItemId);
        }
    }

}

用于测试的示例 JSON 文件(更大的文件会导致更奇怪):

{
  "TypedItemId": 4,
  "Children": [
    {
      "TypedItemId": 67,
      "Children": [
        {
          "TypedItemId": 90,
          "Children": [
            {
              "TypedItemId": 90,
              "Children": [
                {
                  "TypedItemId": 67,
                  "Children": [
                    {
                      "TypedItemId": 90,
                      "Children": [
                        {
                          "TypedItemId": 90,
                          "Children": []
                        },
                        {
                          "TypedItemId": 908,
                          "Children": []
                        }
                      ]
                    },
                    {
                      "TypedItemId": 908,
                      "Children": [
                        {
                          "TypedItemId": 90,
                          "Children": []
                        },
                        {
                          "TypedItemId": 908,
                          "Children": []
                        }
                      ]
                    }
                  ]
                }
              ]
            },
            {
              "TypedItemId": 908,
              "Children": []
            }
          ]
        },
        {
          "TypedItemId": 908,
          "Children": [
            {
              "TypedItemId": 90,
              "Children": []
            },
            {
              "TypedItemId": 908,
              "Children": []
            }
          ]
        }
      ]
    }
  ]
}

PHP 输出(正确):

2/4/67/90/90/67/90/90
2/4/67/90/90/67/90/908
2/4/67/90/90/67/908/90
2/4/67/90/90/67/908/908
2/4/67/90/908
2/4/67/908/90
2/4/67/908/908

JavaScript 节点输出(不正确):

2/4/67/90/90/67/90/90
2/4/67/90/90/67/90/908

【问题讨论】:

  • 您的 JS 代码中没有任何闭包。只是一个正常的功能。
  • 好吧,你仍然对导致不同输出的原因感到好奇。我想知道我不理解的 JavaScript 是什么导致了我看到的结果

标签: javascript php node.js recursion closures


【解决方案1】:

除了您在循环中使用的迭代器之外,您的 JavaScript 没有任何问题:

for (i = 0; i < json.Children.length; i++) {

您使用全局对象上的属性i 作为迭代器,而不是使用var 声明局部变量,它在buildPaths 的所有调用之间共享。

改用局部变量:

for (var i = 0; i < json.Children.length; i++) {

自己试试吧:

var json = {"TypedItemId":4,"Children":[{"TypedItemId":67,"Children":[{"TypedItemId":90,"Children":[{"TypedItemId":90,"Children":[{"TypedItemId":67,"Children":[{"TypedItemId":90,"Children":[{"TypedItemId":90,"Children":[]},{"TypedItemId":908,"Children":[]}]},{"TypedItemId":908,"Children":[{"TypedItemId":90,"Children":[]},{"TypedItemId":908,"Children":[]}]}]}]},{"TypedItemId":908,"Children":[]}]},{"TypedItemId":908,"Children":[{"TypedItemId":90,"Children":[]},{"TypedItemId":908,"Children":[]}]}]}]};

var path = "2";

buildPaths(json, path);

function buildPaths(json, path) {
    if (json.Children == null || json.Children.length == 0) {
        console.log(path + "/" + json.TypedItemId);
    } else {
        for (var i = 0; i < json.Children.length; i++) {
            buildPaths(json.Children[i], path + "/" + json.TypedItemId);
        }
    }
}

【讨论】:

  • 太棒了!! i 是一个全局变量 LOL。现在测试它。 Ty =)
  • 要轻松发现这些类型的错误,请确保使用use strict 启用严格模式。
  • 是的,做到了!感谢您成为我的代码审查眼睛。
  • "use strict"; 会救你的
  • 谢谢大家,两个重要的教训。 “使用严格”;获取更多错误消息,并始终声明所有变量。曾经看过一个演讲,建议在编写 JavaScript 时以 C 风格在函数顶部声明变量,以免自己头疼。我完全倾听并接受了它,就像是的,是的。但是,除非你自己动手,否则你永远不会真正学习 =)
猜你喜欢
  • 2015-01-31
  • 1970-01-01
  • 1970-01-01
  • 2016-11-06
  • 2019-04-11
  • 2013-07-23
  • 2017-05-23
  • 1970-01-01
  • 2020-11-11
相关资源
最近更新 更多