Nested object iteration using multiple for...in Loops.
Tags: javascript, beginners, objects, iteration
Published: 2022-03-23 18:22:49

Nested object iteration was one of the biggest things I struggled to wrap my head around when it was introduced to me during my first month in Flatiron School. It's not that it is an inherently difficult task or that its this incredibly complex task, I just had the hardest time keeping up with where I was within the iteration. In this explanation I will break it down into small chunks that will hopefully help to better understand where you are at within the iteration.

First things first, there are several ways to access object data in JavaScript:

1. Use known keys to access the data manually.
`objName['keyName'] //=> keyValue`  this is useful for user input.
`objName.keyName //=> keyValue` used when exact keyName is known.

2. Use built in functions attached to the Object class to access the data.
`Object.keys(objName)` //=> returns an array of all keys.
`Object.values(objName)` //=> returns an array of all values.
`Object.entries(objName)` //=> returns an array of property arrays.

3. Use a for...in loop to iterate over all keys.

For this example we will be using multiple for...in loops to dive down into our nested objects, however for anyone learning about objects I **HIGHLY** recommend you look up the [mdn](https://developer.mozilla.org/en-US/) on the first two examples listed above.

And with that, I'll get right down to the best possible explanation I can give to a newcomer on nested object iteration:


#Task:

Lets say we have a toy company split up into two teams that each have a their own individual production and sales departments:

```
const toyCompany = {
    redTeam: {
        production: {
            'redProdManager': 'Dan',
            'redWorkerOne': 'Steve',
            'redWorkerTwo': 'Larry'

        },
        sales: {
            'redSalesManager': 'Linda',
            'redSalesOne': 'Tony',
            'redSalesTwo': 'Matt'
        }
    },
    blueTeam: {
        production: {
            'blueProdManager': 'Stacy',
            'blueworkerOne': 'Kevin',
            'blueWorkerTwo': 'Robbie'

        },
        sales: {
            'blueSalesManager': 'Todd',
            'blueSalesOne': 'Jess',
            'blueSalesTwo': 'Nick'
        }
    }
};
```

We've been asked to write a function that finds the job title of an employee given their name as a string.


#First for...in Loop:

To do this, we will begin by making our function `findEmployee()` and adding our first for...in loop. We will also start by adding a `console.log()` in our function to see **EXACTLY** what our first loop is iterating through. We'll then call the function, in this case we'll be searching for an employee by the name `'Todd'`:

```
function findEmployee(stringName) {
    for (const team in toyCompany) {
        console.log(team);
    }
}

findEmployee('Todd');
```
Here is what our `console.log(team)` produced:
`// LOG: redTeam`
`// LOG: blueTeam`

Lets break this for...in loop down a bit. We can see form the LOG statements that our loop iterated through the *first* level of objects within the `toyCompany` variable, the team names (i.e. redTeam, blueTeam). The for loop is essentially saying:
 
*"for each key on the first level of `toyCompany`, I will assign that key to its own variable via `const team` and then perform the code below defined within this loop."*

In our case, the code below is simple the `console.log(team)`. and that is exactly what the code does. For `redTeam`, the loop assigned that name to its own variable using `const team` and then proceeded to the following code, where we then `console.log(team)`. The loop then went on to do the same thing for the next key in that level, `blueTeam`. Since there are only two keys, the loop stopped after that.


#Second for...in Loop:

So we've successfully made it through the first level, but now how do we get to the next level of objects? That's right! another for...in loop! lets add a nested for...in loop to our function and console.log() the results:

```
function findEmployee(stringName) {
    for (const team in toyCompany) {
        const teamObj = toyCompany[team];
        for (const department in teamObj) {
            console.log(department);
        }
    }
}

findEmployee('Todd');
```

Here is what our `console.log(department)` produced:
`// LOG: production`
`// LOG: sales`
`// LOG: production`
`// LOG: sales`

Let's break it down. We've determined that after our first for...in loop we had successfully reached both `redTeam` and `blueTeam`. Remember that everything that happens inside the {curly brackets} after the first for...in loop happens to *one key at a time*. So, all the code will be performed for the `redTeam` **and then** all the code will be performed for the `blueTeam`.

The first thing we've done is declared another variable, `const teamObj = toyCompany[team]`. I know this may seem confusing, but don't overcomplicate it. All this variable is saying is:

*"whichever team key I am currently on in my first for...in loop iteration, I will assign all object data inside of that key to the variable of `teamObj`."*

If you were to `console.log(teamObj)` you would see: `{production: {...}, sales: {...}}` which is everything *inside* of either team object, hence the name `teamObj`.

This means we have now reached the department level of the nested objects (i.e. production, sales). Now that we can reference the department level of objects via the variable `teamObj`, we are set up to iterate through them via the next for...in loop: 

`for (const department in teamObj) {}` this loop is simply saying:

*"for each key on the first level of `teamObj`, I will assign that key to its own variable via `const department` and then perform the code below defined within this loop."*

When we `console.log(department)` we see that each department (i.e. production, sales) is logged twice. This is because the first loop starts in the `redTeam` and the second loop console log's both `production` and `sales`. The first loop then moves to the `blueTeam` and the second loop runs its code again, console logging both `production` and `sales`. 


#Third (and Final) for...in Loop:

Now we can dive down into our final loop to reach the last level of nested objects and find Todd. Lets take a look at the code below:

```
function findEmployee(employeeName) {
    for (const team in toyCompany) {
        const teamObj = toyCompany[team];
        for (const department in teamObj) {
            const jobTitleObj = teamObj[department];
            for (const jobTitle in jobTitleObj) {
                if (jobTitleObj[jobTitle] === employeeName) {
                    console.log(jobTitle);
                }
            }
        }
    }
};
```

Our result:
`// LOG: blueSalesManager`

If you understand how the second loop worked, the third is simply a repetition with a slight change of code at the end. lets walk through it.

Our second for...in loop has gotten us down to the department level of objects (i.e. production, sales). The third loop will get us to the employees. Again we declare a variable `const jobTitleObj = teamObj[department]` which assigns a variable to the third level of objects that contains a job title key with a matching employee name variable. A quick `console.log(jobTitleObj)` would yield four LOG's, each with an object containing three properties, one for each job within the department. Here's an example of the first of four LOG's:

`// LOG: {redProdManager: Dan, redWorkerOne: Steve, redWorkerTwo: Larry}`

Next we have our third for...in loop that basically says:

*"for each key on the first level of `jobTitleObj`, I will assign that key to its own variable via `const jobTitle` and then perform the code below defined within this loop."*

Again, this is nothing different than the second for...in loop. 

Now that we have access to the job title key via the `jobTitle` variable, we use an if statement and square brackets to check each `jobTitle` key and see what the value is, aka the employee name. We do this by using the object name followed by square brackets with the key name inside (`objName[keyName]`). If we were to add `console.log(jobTitleObj[jobTitle])` after the third for...in loop, it would yield a list of 12 LOG's with each employees name, showing that we can access the name of each employee using bracket notation. 

The if statement is basically saying:

*"If the employees name attached to the current key I am on(`jobTitleObj[jobTitle]`) is equal to the `employeeName` provided when the function was called, then LOG that persons job title (`console.log(jobtitle)`)."*

and upon calling `findEmployee('Todd');` you will see the result as `blueSalesManager` which, if we scroll up to our starting data, we see is correct!


#Conclusion:

I'll conclude this post by saying that I am very aware there are much more code-efficient ways to go about accomplishing this task, however, for learning purposes as a beginner, this method helps understand the basics of how things are working. It proved to be a rather steep learning curve for myself and probably is for others I can imagine. Hope this explanation helps!

Happy coding and happy learning!