非递归代码递归

时间:2017-05-13 14:37:56

标签: javascript jquery function recursion tree

以下代码应该创建一个简单的"树",但它会变成递归和崩溃。

        var cnt = 0;
        var page = {
            properties: {},
            folders: [],
            items: []
        };

        function createPage() {
            var ret = $.extend({}, page);
            ret.cnt = cnt++;
            return  ret;
        }
        var tree = createPage();

        function addFolders(f, n) {
            for (var i = 0; i < n; i++) {
                f.push(createPage());
            }
        }


        function createData() {
            addFolders(tree.folders, 4);
            for (var i = 0; i < tree.folders.length; i++) {
                addFolders(tree.folders[i].folders, i);
            }
        }

        createData();

有人可以解释为什么会这样吗?

3 个答案:

答案 0 :(得分:2)

斜视是正确的,脚本总是推送到相同的folders数组,导致长度不断增加并且永远不会离开循环。您可以将createPage功能更改为:

function createPage() {
  return {
      properties: {},
      cnt: cnt++,
      folders: [],
      items: []
  };
}

答案 1 :(得分:2)

$.extend({}, page);执行page对象的浅表副本。

var secondPage = $.extend({}, page);
console.log(page === secondPage); // false
console.log(page.folders === secondPage.folders); // true!!

createData循环遍历tree.folders时,它也会对其进行修改,因此每次迭代tree.folders.length只会增加。

您可以将其他选项传递给$.extenddo a deep extend $.extend(true, {}, page)

var secondPage = $.extend(true, {}, page);
console.log(page === secondPage); // false
console.log(page.folders === secondPage.folders); // false

答案 2 :(得分:1)

问题: 您的$.extend没有进行深层复制,因此子文件夹始终是对相同根文件夹的引用。执行此操作var ret = $.extend(true, {}, page);或直接在createPage()中使用对象文字。它只是一个浅的副本。不会复制引用两个数组和对象的属性。这些是参考文献。

复制/测试:console.log(page.folders.length)放在createPage()内。您将看到原始folders对象的page发生了变异。好主意让一个计数器在达到100时会抛出一个错误,以致它无法无限递归。此外,使用开发人员工具在代码运行时逐步执行。

解决方案: 原始外部对象保留在浅层。但你不只是改变外部物体;你正在改变外部对象引用的对象。这就是我在上面展示的deep选项的原因。因此,当您推送到副本的.folders时,您将推送到原始文件的.folders,因为它没有复制它;它为外部副本分配了一个引用。

这是一个更简单的演示:jsfiddle.net/zazvkvmh