如何理解这段代码的运行?

  function createTree(deep) {
            let children = {};
            let tree = { id: 0 ,children};
            for (let i = 1; i <= deep; i++) {
                children.id = i;
                children.children = {}
                children = children.children; //不太理解这里
            }
            return tree;
        }
        let tree = createTree(6);

看他每次循环都只生成了一个节点,怎么把他遍历到tree中的呢?

阅读 2.1k
3 个回答

image.png

为防止混淆改一下, children 改为了 obj

  function createTree (deep) {
    let obj = {};
    let tree = { id: 0, obj };
    for (let i = 1; i <= deep; i++) {
      obj.id = i;
      // 给obj新建一个名字为children的键, 值为空对象
      obj.children = {}
    // 使用倒叙创建了 children 给obj, 
      // 然后将变量obj的值改为上面上面的新建的children, 其实就是改变了其指向
      obj = obj.children;
    }
    return tree;
  }
  let tree = createTree(6);
  console.log(tree);

image.png

其实就是一个值累加的过程,如果将这个过程看做是一个加法运算的话,那么代码如下:

function createTree(deep) {
  // let children = {}; // 忽略掉这个变量
  let tree = 0; // 这个就是最终结果,为了方便理解过程,变量名保持不变,其实应该命名为 sum
  for (let i = 1; i <= deep; i++) {
    // 这里就是一个求值的过程
    // children.id = i;
    // children.children = {}
    // children = children.children;

    // 因为这里干掉了 children 变量,所以求值过程就直接变成操作 tree 变量了
    tree = tree + i;
  }

  // 最终返回 tree 变量,也就是最终结果
  return tree;
}

// 现在拿到了最终结果,也就是 1 + 2 + 3 + 4 + 5 + 6 = 21
let tree = createTree(6);

现在这个 tree 并不是一个树形结构,而是一个数字

但是我们可以通过下面的方法,将这个数字转换成一个树形结构

但是可以看到求值过程是 0+1=1 > 1+2=3 > 3+3=6 > 6+4=10 > 10+5=15 > 15+6=21 这个是有层级关系的

所以 children = children.children 这个操作就是保留了层级关系

如果我们也将这个过程保留下来,但是不用是树形结构,而是一个数组,代码如下:

function createTree(deep) {
  let children = 0; // 放开这个变量,但是数据类型变成了数字
  let tree = []; // 将这个变量的数据类型变成了数组,因为现在最终的结果是一个数组,存储的是计算过程
  for (let i = 1; i <= deep; i++) {
    // 这里就是一个求值的过程
    children = children + i;

    // 将当前计算的结果放到 tree 中
    tree.push(children)
  }

  // 最终返回 tree 变量,也就是最终结果
  return tree;
}

// 现在拿到了最终结果,也就是一个数组[1, 3, 6, 10, 15, 21]
let tree = createTree(6);

想想看children = children + ichildren = children.children这两个操作是不是有点像?

有没有找到那么一点感觉?没有没关系,再将这个数组的数据结构丰富一下:

function createTree(deep) {
  let children = {
    current: 0,
    result: 0,
  };
  let tree = []; // 将这个变量的数据类型变成了数组,因为现在最终的结果是一个数组,存储的是计算过程
  for (let i = 1; i <= deep; i++) {
    // 这里就是一个求值的过程
    children.current = i;
    children.result = children.current + children.result;

    // 将当前计算的结果放到 tree 中
    tree.push(children)
  }

  // 最终返回 tree 变量,也就是最终结果
  return tree;
}

// 现在拿到了最终结果,但是结果有点不对劲
let tree = createTree(6);
console.log(tree);

image.png

可以看到的是数组中的每一项的结果都是相同的,因为 children是一个对象,对象是一个引用值

引用值不知道是什么意思建议去查查资料,这里不多介绍

这道这个特性就有趣了,现在将你说的不理解的代码加上去试试看:

function createTree(deep) {
  let children = {
    current: 0,
    result: 0,
  };
  let tree = []; // 将这个变量的数据类型变成了数组,因为现在最终的结果是一个数组,存储的是计算过程
  for (let i = 1; i <= deep; i++) {
    // 这里就是一个求值的过程
    children.current = i;
    children.result = children.current + children.result;

    // 将当前计算的结果放到 tree 中
    tree.push(children)

    // 这两步要放到一起看,这里会有一个 result 记录上一个节点的结果值,所以会有一个初始化的过程
    children.children = {
      current: 0,
      result: children.result,
    }
    children = children.children
  }

  // 最终返回 tree 变量,也就是最终结果
  return tree;
}

// 现在拿到了最终结果,但是结果有点不对劲
let tree = createTree(6);
console.log(tree);

image.png

有趣的事情出现了,在数组的第一项中是有完整的执行过程的,数组数组的第二项记录的就是从第二项开始的执行过程,依次类推

可以看到的是数组每一项都是一个树形结构,在原始代码中需要就是一个树形数据结构,但是对深度有要求,符合条件的就是第一项,那么把第一项返回就好了

将数组改回对象形式,第一项就是第一次求值,不需要push,直接在最开始塞进 tree 这个对象里面去就好了,也就是你最开始提供的代码;

这段代码的运行你可以这样理解:
首先,创建一个空对象 children,然后创建一个对象 tree,它有两个属性:id 和 children,其中 id 的值为 0,children 的值为 children 对象的引用。
然后,进入一个 for 循环,循环的次数为 deep,也就是要创建的树的深度。在每次循环中,给 children 对象添加两个属性:id 和 children,其中 id 的值为 i,children 的值为一个空对象。然后,将 children 变量重新赋值为 children 对象的 children 属性的引用,也就是指向下一层的空对象。
这样,每次循环都会在上一层的 children 对象中添加一个新的 children 对象,并将 children 变量指向它。最终,形成了一个嵌套的对象结构,类似于这样:

{
  "id": 0,
  "children": {
    "id": 1,
    "children": {
      "id": 2,
      "children": {
        "id": 3,
        "children": {
          "id": 4,
          "children": {
            "id": 5,
            "children": {
              "id": 6,
              "children": {}
            }
          }
        }
      }
    }
  }
}

最后,返回 tree 对象作为结果。
可以看到,这段代码实际上是创建了一个单链表结构,每个节点只有一个子节点。如果要创建一个真正的树结构,需要在每层添加多个子节点,并且使用数组来存储子节点。

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题