代码之家  ›  专栏  ›  技术社区  ›  GNETO DOMINIQUE

带对象的for循环

  •  5
  • GNETO DOMINIQUE  · 技术社区  · 6 年前

    我在下面看到的代码将嵌套对象的所有块的指定属性值添加到 数组调用的数组 . 我的问题是我不理解迭代如何在像下面这样的嵌套对象中工作 for循环 .

    有人能向我解释一个对象如何实现for循环迭代吗?

    let list = {
       value: 1,
       rest: {
          value: 2,
          rest: {
             value: 3,
             rest: null
        }
      }
    };
    

    以下是执行此项工作的功能

    function listToArray(list) {
      let arrays = [];
      for (let node = list; node; node = node.rest) { // big question: how it works or possible?
        arrays.push(node.value);
      }
      return arrays;
    }
    console.log(listToArray(list)); // -> [1, 2, 3]
    
    6 回复  |  直到 6 年前
        1
  •  3
  •   ibrahim mahrir    6 年前

    如何做 for 循环工作:

    首先你需要了解 for 循环工作。

    for语句创建一个循环,该循环由三个可选表达式组成,用括号括起来并用分号分隔,后跟一个要在循环中执行的语句(通常是块语句)。 MDN

    这个 对于 循环具有以下结构:

    for ([initialization]; [condition]; [final-expression])
       statement
    

    表达式 initialization , condition final-expression 可以是任何有效表达式。任何或所有这些表达式都可以省略( for(;;) 在javascript中有效,并创建无限循环)。

    这个 对于 循环开始于执行 初始化 如果指定了表达式,则重复以下操作:检查 条件 是真的,如果是真的,那么它就执行 statement (S)和 最终表达式 按顺序,如果 条件 它会停止循环。

    下面是一个例子,下图 ( image source ) :

    for loop diagram

    对应于以下内容 对于 循环:

    for(i = 2; i <= 6; i = i + 2)
      print i + 1
    

    注意到 初始化 部分 i = 2 只执行一次,而其余的 条件 部分 i <= 6 , the 陈述 (s)零件和 最终表达式 i = i + 2 )可以执行多次(按顺序),具体取决于 条件 .

    有关代码的解释:

    for (let node = list; node; node = node.rest) { // big question: how it works or possible?
      arrays.push(node.value);
    }
    

    这个 初始化 此循环的一部分只声明变量 node 并将其值设置为根元素 list ,当循环即将开始时,此部分只执行一次。

    这个 条件 零件检查是否 结点 (变量)是 truthy 或者不,在javascript中,对象是真实的,而 undefined 不是,是一个 falsy 价值观(当然还有其他真实和不可靠的价值观,但对于这个特定的例子,我们只对这两个价值观感兴趣)。循环的概念是将对象从一个节点运行到另一个节点(请参见 最终表达式 部分波纹管)。当子节点存在时,下一个值为 结点 将是那个节点(它是一个对象),这意味着它将是一个真实的值,因此条件将是真的。但是如果子节点不存在, 结点 未定义 (一个错误的值),因此条件将是错误的。

    这个 最终表达式 只需设置 结点 到当前节点的子节点 node.rest . 如果它存在 结点 将是一个对象,否则将是 未定义 .

        2
  •  1
  •   Nino Filiu    6 年前

    for 可以看作是 while ,即使存在一些低级差异,这些差异也是相同的:

    for (let i=0; i<10; i++) {
      console.log(i);
    }
    
    let i=0;
    while(i<10) {
      console.log(i);
      i++;
    }

    句法 对于 for(initialization, test, iteration) . 这是:

    for (let node = list; node; node = node.rest) { doSomething(node); }
    

    如果这样写可能更容易理解:

    let node = list;
    while(node) { // equivalent to: while(node!==null) {
      doSomething(node);
      node = node.rest;
    }
    
        3
  •  1
  •   Andrey Antipov    6 年前

    for循环由三部分组成

    1. 初始化-将调用一次( let node=list )
    2. 条件继续-将在每次迭代时调用( node )
    3. 下一步-将在 返回 true . 通常要更新在

    让我们更仔细地看看这里到底发生了什么:

    for(let node = list; node; node=node.rest)
    

    首先,您要创建一个名为 结点 价值 list
    接下来,您将检查当前是否 null undefined . 这两个值都不稳定,这意味着它们都会返回 false 当它们被强制为布尔值时。如果不是,你的 arrays.push 将执行,否则将终止循环。
    最后,您正在更新 结点 值为 node.rest . 在你之前 排列 将使用更新的 结点 ,将再次检查您的状况。
    最后,当你 结点

    {
       value: 3,
       rest: null
    }
    

    你的 循环的一部分将更新 结点 变量分配 rest 对,那就是 无效的 你的 不会通过,所以会终止

        4
  •  1
  •   Shidersz    6 年前

    作为引言,首先注意for循环有以下语法:

    for (statement 1; statement 2; statement 3) {
        // code block to be executed
    }
    
    1. Statement 1 在代码块执行之前执行(一次)。
    2. Statement 2 定义执行代码块的条件。
    3. Statement 3 在代码块执行之后执行(每次)。

    所以,在每次迭代中,您都要深入到 tree 具有 node = node.rest . 循环停止,因为最终您将尝试访问属性 rest 对一些 node 没有那个 钥匙 或被设置为 null ,这将被评估为 undefined 无效的 分别和自停止条件 for 循环是测试变量 结点 它会在这个时候停止 未定义 无效的 (注意这些是 falsy javascript上的值)。

    调试示例 :

    let list = {
       value: 1,
       rest: {
          value: 2,
          rest: {
             value: 3,
             rest: null
        }
      }
    };
    
    function listToArray(list)
    {
        let arrays = [];
        
        for (let node = list; node; node = node.rest)
        {
            console.log("Current node is: " + JSON.stringify(node));
            console.log("Node value is: " + node.value);
            arrays.push(node.value);
            console.log("Next node will be: " + JSON.stringify(node.rest));
        }
    
        return arrays;
    }
    
    console.log(listToArray(list));
        5
  •  0
  •   Mr. Polywhirl    6 年前

    您也可以使这个递归,因为这样更容易解释。

    如果你的目标是 null ,只需返回数组(如它所示),否则将调用返回到下一个 rest 并添加 value 数组。

    obj = { value: 1, rest: {...} }, arr = []          // Add 1 to arr and return obj.rest
    obj = { value: 2, rest: {...} }, arr = [ 1 ]       // Add 2 to arr and return obj.rest
    obj = { value: 3, rest: null  }, arr = [ 1, 2 ]    // Add 3 to arr and return null
    obj = null,                      arr = [ 1, 2, 3 ] // Return arr [ 1, 2, 3 ]
    

    let list = {
      value: 1,
      rest: {
        value: 2,
        rest: {
          value: 3,
          rest: null
        }
      }
    };
    
    function listToArray(obj, arr = []) {
      return obj == null ? arr : listToArray(obj.rest, arr.concat(obj.value));
    }
    
    console.log(listToArray(list)); // -> [1, 2, 3]
    .as-console-wrapper { top: 0; max-height: 100% !important; }
        6
  •  0
  •   Jonas Wilms    6 年前

    假设您要访问包含 value: 3 . 然后你会这样做:

     list.rest.rest // { value: 3, rest: null }
    

    您也可以将其写进多行,如下所示:

     let node = list; // { value: 1, rest: { ... } }
     node = node.rest; // { value: 2, rest: { ... } }
     node = node.rest; // { value: 3, rest: null }
    

    这可以推广为n次重复

     for(let node = list; node; node = node.rest) {
       //...
     }
    

    现实世界示例:

    你住在一个小村庄里,从北到南只有一条街道。这条街旁边有几所房子。你住在小镇的尽头,北端。你邻居叫鲍勃。鲍勃还有一个邻居叫爱丽丝。爱丽丝有个邻居叫夏娃。现在,如果你想沿着这条街走,你可以先去看看鲍勃,再去看看爱丽丝,再去看看夏娃。或者你只是走到下一所房子,直到你到达小镇的尽头。

     const bob = you.southernNeighbour;
     const alice = bob.southernNeighbour;
     const eve = alice.southernNeighbour;
    
     // ...
    
    let current = you; // you start where you are.
    while(current) // as long as there is a house, walk 
      current = current.southernNeighbour; // go to the next southern neighbour