Question

How to Loop Through a JavaScript Object of Nested Objects

Question

How can I loop through every property in a plain JavaScript object when the values are themselves objects?

For example, given this object:

const validation_messages = {
  key_1: {
    your_name: "jimmy",
    your_msg: "hello world"
  },
  key_2: {
    your_name: "billy",
    your_msg: "foo equals bar"
  }
};

How can I iterate over each top-level entry and access the nested values like your_name and your_msg for each one?

Short Answer

By the end of this page, you will understand how to loop through a JavaScript object whose properties contain other objects. You will learn the most common iteration techniques, how to access nested values safely, and which approach is best in real code.

Concept

In JavaScript, a plain object stores data as key-value pairs. Sometimes the value for each key is another object. This creates a structure often called an object of objects.

In your example, the top-level object has keys like key_1 and key_2. Each of those keys points to another object containing fields like your_name and your_msg.

To work with this structure, you usually:

  1. Loop through the top-level object
  2. Read each nested object
  3. Access the properties inside that nested object

This matters because many real programs use nested objects for:

  • API responses
  • configuration data
  • form validation messages
  • lookup tables
  • grouped records by ID or name

A key thing to remember is that objects are not arrays. You do not loop through them with array indexes like obj[0], obj[1], and so on. Instead, you iterate over their property names using tools such as:

  • for...in
  • Object.keys()
  • Object.values()
  • Object.entries()

For beginner-friendly and modern JavaScript, Object.entries() is often the clearest choice when you need both the key and the nested value object.

Mental Model

Think of a JavaScript object like a cabinet of labeled drawers.

  • The outer object is the cabinet.
  • Each top-level key such as key_1 or key_2 is a drawer label.
  • Inside each drawer is another small record card.
  • That record card has fields like your_name and your_msg.

Looping through the object means:

  1. Open each drawer
  2. Read the card inside
  3. Pull out the fields you need

So for key_1, you open the drawer labeled key_1, then read:

  • your_name → jimmy
  • your_msg → hello world

The same process repeats for every drawer in the cabinet.

Take Quiz

Syntax and Examples

A common modern way to loop through an object of objects is Object.entries().

const validation_messages = {
  key_1: {
    your_name: "jimmy",
    your_msg: "hello world"
  },
  key_2: {
    your_name: "billy",
    your_msg: "foo equals bar"
  }
};

for (const [key, value] of Object.entries(validation_messages)) {
  console.log(key); // key_1, key_2
  console.log(value.your_name);
  console.log(value.your_msg);
}

What this does

  • Object.entries(validation_messages) converts the object into an array of pairs.
  • Each pair looks like [key, value].
  • key is the top-level property name.
  • value is the nested object.

Example output

key_1
jimmy
hello world
key_2
billy
foo equals bar

Using for...in

You can also use for...in:

for (const key in validation_messages) {
  const message = validation_messages[key];
  console.log(key);
  console.log(message.your_name);
  console.log(message.your_msg);
}

This works, but in real projects you often add a safety check when using for...in.

for (const key in validation_messages) {
  if (Object.hasOwn(validation_messages, key)) {
    const message = validation_messages[key];
    console.log(message.your_name, message.your_msg);
  }
}

Using Object.values() when you only need nested objects

for (const message of Object.values(validation_messages)) {
  console.log(message.your_name);
  console.log(message.your_msg);
}

Use this when you do not need the outer keys like key_1 and key_2.

Step by Step Execution

Consider this code:

const validation_messages = {
  key_1: {
    your_name: "jimmy",
    your_msg: "hello world"
  },
  key_2: {
    your_name: "billy",
    your_msg: "foo equals bar"
  }
};

for (const [key, message] of Object.entries(validation_messages)) {
  console.log(`Current key: ${key}`);
  console.log(`Name: ${message.your_name}`);
  console.log(`Message: ${message.your_msg}`);
}

Step by step

  1. Object.entries(validation_messages) runs.
  2. It produces an array like this:
[
  ["key_1", { your_name: "jimmy", your_msg: "hello world" }],
  ["key_2", { your_name: "billy", your_msg: "foo equals bar" }]
]
  1. The loop starts with the first entry:
    • key becomes "key_1"
    • message becomes { your_name: "jimmy", your_msg: "hello world" }
  2. message.your_name gives "jimmy"
  3. message.your_msg gives "hello world"
  4. The loop moves to the second entry:
    • key becomes "key_2"
    • message becomes { your_name: "billy", your_msg: "foo equals bar" }
  5. message.your_name gives "billy"
  6. message.your_msg gives "foo equals bar"
  7. The loop ends after all object properties have been processed.

Trace table

Iterationkeymessage.your_namemessage.your_msg
1key_1jimmyhello world
2key_2billyfoo equals bar

Real World Use Cases

Objects containing other objects appear often in real applications.

API response data

const usersById = {
  u101: { name: "Ava", role: "admin" },
  u102: { name: "Noah", role: "editor" }
};

You might loop through this to render user cards.

Validation errors by field

const errors = {
  email: { message: "Email is required" },
  password: { message: "Password is too short" }
};

You might iterate through this to show form errors.

Configuration groups

const config = {
  database: { host: "localhost", port: 5432 },
  cache: { enabled: true, ttl: 300 }
};

You might inspect or log settings when starting an app.

Product lookup maps

const products = {
  p1: { name: "Keyboard", price: 50 },
  p2: { name: "Mouse", price: 25 }
};

You might loop through products to build a list or compute totals.

Take Quiz

Real Codebase Usage

In real projects, developers often choose the object iteration method based on what they need.

1. Object.entries() for readable iteration

This is common when both the key and value matter.

for (const [id, user] of Object.entries(usersById)) {
  console.log(id, user.name);
}

2. Object.values() when only values matter

This avoids unused variables.

const names = Object.values(usersById).map(user => user.name);

3. Guard clauses for missing nested data

Real data is not always complete.

for (const [key, item] of Object.entries(validation_messages)) {
  if (!item) continue;
  if (!item.your_name || !item.your_msg) continue;

  console.log(item.your_name, item.your_msg);
}

4. Validation before processing

function printMessages(data) {
  if (!data || typeof data !== "object") {
    return;
  }

  for (const [key, value] of Object.entries(data)) {
    console.log(key, value);
  }
}

5. Transforming object data into arrays

Developers often convert object data into arrays so they can use map, filter, and reduce.

const messageList = Object.entries(validation_messages).map(([key, value]) => {
  return {
    id: key,
    name: value.your_name,
    message: value.your_msg
  };
});

This pattern is very common in frontend apps and API formatting.

Common Mistakes

Mistake 1: Treating an object like an array

Broken code:

for (let i = 0; i < validation_messages.length; i++) {
  console.log(validation_messages[i]);
}

Why it fails:

  • Plain objects do not have a length property by default.
  • Their keys are not numeric indexes unless you explicitly use them that way.

Use this instead:

for (const [key, value] of Object.entries(validation_messages)) {
  console.log(key, value);
}

Mistake 2: Accessing nested properties on the wrong object

Broken code:

for (const key in validation_messages) {
  console.log(validation_messages.your_name);
}

Why it fails:

  • your_name is not a property of the outer object.
  • It belongs to each nested object.

Correct version:

for (const key in validation_messages) {
  const item = validation_messages[key];
  console.log(item.your_name);
}

Mistake 3: Forgetting the correct property name

Your original text mentions your_message, but the object uses your_msg.

Broken code:

console.log(item.your_message);

This gives undefined because the property does not exist.

Correct version:

console.log(item.your_msg);

Mistake 4: Using for...in without understanding inherited properties

for...in iterates over enumerable properties, including inherited ones.

Safer version:

for (const key in validation_messages) {
  if (Object.hasOwn(validation_messages, key)) {
    console.log(validation_messages[key]);
  }
}

Mistake 5: Not checking for missing nested values

Broken code:

const data = {
  key_1: null
};

for (const [key, value] of Object.entries(data)) {
  console.log(value.your_name);
}

This crashes because value is null.

Safer version:

for (const [key, value] of Object.entries(data)) {
  if (!value) continue;
  console.log(value.your_name);
}

Comparisons

ApproachBest whenGets key?Gets value?Notes
for...inYou want classic object iterationYesYes, via obj[key]May include inherited properties unless checked
Object.keys()You only need property namesYesIndirectlyOften used with for...of
Object.values()You only need the nested objectsNoYesClean when keys are not needed
Object.entries()You need both keys and valuesYesYesOften the clearest modern option

Example comparison

const data = {
  key_1: { your_name: "jimmy", your_msg: "hello world" },
  key_2: { your_name: "billy", your_msg: "foo equals bar" }
};

Using Object.keys():

for (const key of Object.keys(data)) {
  console.log(key, data[key].your_name);
}

Using Object.values():

for (const value of Object.values(data)) {
  console.log(value.your_name);
}

Using Object.entries():

for (const [key, value] of Object.entries(data)) {
  console.log(key, value.your_name);
}

Objects vs arrays

FeatureObjectArray
Data accessBy property nameBy numeric index
Typical useNamed records or mapsOrdered lists
Common loop toolsfor...in, Object.keys, Object.entriesfor, for...of, map, filter
Take Quiz

Cheat Sheet

Loop through an object of objects

for (const [key, value] of Object.entries(obj)) {
  console.log(key, value.someProperty);
}

Get only keys

Object.keys(obj)

Get only values

Object.values(obj)

Get keys and values

Object.entries(obj)

for...in pattern

for (const key in obj) {
  if (Object.hasOwn(obj, key)) {
    console.log(key, obj[key]);
  }
}

Access nested properties

obj[key].your_name
obj[key].your_msg

Safe access idea

if (obj[key]) {
  console.log(obj[key].your_name);
}

Best default choice

  • Use Object.entries() when you need both key and nested object.
  • Use Object.values() when you only need the nested object.
  • Use Object.keys() when you only need the property names.

Watch out for

  • Objects are not arrays
  • Property names must match exactly
  • for...in can include inherited properties
  • Nested values may be null or missing

FAQ

How do I loop through a JavaScript object with nested objects?

Use Object.entries() or for...in to iterate over the top-level object, then access properties on each nested object.

for (const [key, value] of Object.entries(data)) {
  console.log(value.your_name);
}

What is the best way to iterate over object properties in JavaScript?

For modern JavaScript, Object.entries() is usually the clearest when you need both keys and values.

Can I use map() directly on an object?

No. map() is an array method. Convert the object first with Object.keys(), Object.values(), or Object.entries().

Why does validation_messages.length not work?

Because plain objects do not have a built-in length property like arrays do.

What is the difference between for...in and for...of?

  • for...in iterates over object property names.
  • for...of iterates over iterable values like arrays, strings, and the arrays returned by Object.entries().

How do I get both the key and the nested object value?

Use Object.entries():

for (const [key, value] of Object.entries(data)) {
  console.log(key, value);
}

What if a nested object property is missing?

Check that the nested object exists before reading its properties.

if (value && value.your_name) {
  console.log(value.your_name);
}
Take Quiz

Mini Project

Description

Build a small script that prints a contact directory stored as an object of objects. This demonstrates how to loop through top-level object keys and read nested properties from each entry.

Goal

Create a program that iterates through an object of contacts and prints each contact's ID, name, and message.

Requirements

  1. Create a plain JavaScript object with at least three top-level keys.
  2. Store an object as the value of each top-level key.
  3. Include your_name and your_msg inside each nested object.
  4. Loop through all entries and print the key, name, and message.
  5. Skip any entry whose value is missing or null.
Take Quiz

Keep learning

Related questions

View more