GNETO DOMINIQUE
GNETO DOMINIQUE

Reputation: 677

For loop with object

I come across this code below which add a specified property value of all block of a nested object to an array called arrays. My problem is that I don' t understand how iteration works in a nested object like the one below using for loop.

Can someone explain to me how for loop iteration is possible with an object?

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

below is the function that does the job

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]

Upvotes: 5

Views: 572

Answers (6)

ibrahim mahrir
ibrahim mahrir

Reputation: 31712

How do for loops work:

First you need to understand how for loops works.

The for statement creates a loop that consists of three optional expressions, enclosed in parentheses and separated by semicolons, followed by a statement (usually a block statement) to be executed in the loop. MDN

The for loop has this structure:

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

The expressions initialization, condition and final-expression could be any valid expression. Any or all of these expressions could be omitted (for(;;) is valid in javascript and it creates an infinite loop).

The for loop begins by executing the initialization expression if specified, then repeats the following actions: check if the condition is truthy, if so then it executes statement(s) and final-expression in order, if the condition is falsy it stops looping.

Here is an example, the following diagram (image source):

for loop diagram

Corresponds to the follwing for loop:

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

Notice that the initialization part i = 2 is only executed once whereas the rest (the condition part i <= 6, the statement(s) part and the final-expression i = i + 2) could be executed multiple times (in order) depending on the condition.

Explanation of the code in question:

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

The initialization part of this loop just declares the variable node and sets its value to the root element list, this part is only executed once, when the loop is about to start.

The condition part checks whether node (the variable) is truthy or not, in javascript an object is truthy whereas undefined is not, it's a falsy value (there are other truthy and falsy values of course but we are only interested in these two for this particular example). The concept of the loop is running down the object from node to node (see the final-expression part bellow). When a child node exists, the next value of node will be that node (which is an object), that means it's gonna be a truthy value, hence the condition will be true. Whereas if the child node doesn't exists, node will be undefined (a falsy value) and thus the condition will be falsy.

The final-expression just sets the value of node to the child node of the current node which is node.rest. If it exists node will be an object, otherwise it will be undefined.

Upvotes: 4

Shidersz
Shidersz

Reputation: 17190

As an introduction, first note the for loop has the following syntax:

for (statement 1; statement 2; statement 3) {
    // code block to be executed
}
  1. Statement 1 is executed (one time) before the execution of the code block.
  2. Statement 2 defines the condition for executing the code block.
  3. Statement 3 is executed (every time) after the code block has been executed.

So, on every iteration you are going one level deep of the tree with node = node.rest. The loop stops because eventually you will try to access property rest on some node that don't have that key or is set to null, this will be evaluated to undefined or null respectively, and since the stop condition of the for loop is to test the variable node it will stop when this is undefined or null (Note these are falsy values on Javascript).

Example with debug:

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));

Upvotes: 1

Andrey Antipov
Andrey Antipov

Reputation: 410

For loop consists of three parts

  1. initialization - will be called once (let node=list)
  2. condition to continue - will be called on each iteration (node)
  3. next step - will be called when a 2 returned true. Usually you want to update a variable created in the 1

Let's have a closer look at what is actually happening here:

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

First, you are creating a new variable called node with the value of list
Next, you are checking if your isn't currently null or undefined. Theese two values are falsy, which means they both returns false when they are coerced to a boolean. If it's not, your arrays.push will be executed, otherwise your loop will be terminated.
Last, you are updating your node with a value of the node.rest. Before your arrays.push will be executed with the updated node, your condition will be checked again.
Finally, when your node is

{
   value: 3,
   rest: null
}

your 3 part of the loop will update the node variable assigning rest to it, which is null and your 2 won't pass, so it'll be terminated

Upvotes: 1

Jonas Wilms
Jonas Wilms

Reputation: 138567

Let's say you want to access the nested object containing value: 3. Then you'd do:

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

You could also write that into multiple lines as:

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

and that can be generalized for n repetitions as

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

Real world example:

You are living in a small village, there is only one street from north to south. There are a few houses next to the street. You are living at the end of the small town, at the northern end. Your neighbour's name is Bob. Bob also got a neighbour called Alice. Alice got a neighbour called Eve. Now if you want to walk along the street , you could either visit Bob, then Alice, then Eve. Or you just walk to the next house until you reached te end of the little town.

 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

Upvotes: 0

Nino Filiu
Nino Filiu

Reputation: 18561

for can be viewed as a syntactical sugar for while, even if there are a few low-level differences, these are the same:

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

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

The syntax of for is for(initialization, test, iteration). This:

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

Is perhaps easier to understand if written as this:

let node = list;
while(node) { // equivalent to: while(node!==null) {
  doSomething(node);
  node = node.rest;
}

Upvotes: 0

Mr. Polywhirl
Mr. Polywhirl

Reputation: 48751

You can also make this recursive, as this makes it easier to explain.

If your object is null, just return the array (as it stands), else return a call to the next rest and add the value to the array.

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; }

Upvotes: 0

Related Questions