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:
- Loop through the top-level object
- Read each nested object
- 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...inObject.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_1orkey_2is a drawer label. - Inside each drawer is another small record card.
- That record card has fields like
your_nameandyour_msg.
Looping through the object means:
- Open each drawer
- Read the card inside
- Pull out the fields you need
So for key_1, you open the drawer labeled key_1, then read:
your_name→jimmyyour_msg→hello world
The same process repeats for every drawer in the cabinet.
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]. keyis the top-level property name.valueis 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
Object.entries(validation_messages)runs.- 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" }]
]
- The loop starts with the first entry:
keybecomes"key_1"messagebecomes{ your_name: "jimmy", your_msg: "hello world" }
message.your_namegives"jimmy"message.your_msggives"hello world"- The loop moves to the second entry:
keybecomes"key_2"messagebecomes{ your_name: "billy", your_msg: "foo equals bar" }
message.your_namegives"billy"message.your_msggives"foo equals bar"- The loop ends after all object properties have been processed.
Trace table
| Iteration | key | message.your_name | message.your_msg |
|---|---|---|---|
| 1 | key_1 | jimmy | hello world |
| 2 | key_2 | billy | foo 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.
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
lengthproperty 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_nameis 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
| Approach | Best when | Gets key? | Gets value? | Notes |
|---|---|---|---|---|
for...in | You want classic object iteration | Yes | Yes, via obj[key] | May include inherited properties unless checked |
Object.keys() | You only need property names | Yes | Indirectly | Often used with for...of |
Object.values() | You only need the nested objects | No | Yes | Clean when keys are not needed |
Object.entries() | You need both keys and values | Yes | Yes | Often 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
| Feature | Object | Array |
|---|---|---|
| Data access | By property name | By numeric index |
| Typical use | Named records or maps | Ordered lists |
| Common loop tools | for...in, Object.keys, Object.entries | for, for...of, map, filter |
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...incan include inherited properties- Nested values may be
nullor 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...initerates over object property names.for...ofiterates over iterable values like arrays, strings, and the arrays returned byObject.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);
}
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
- Create a plain JavaScript object with at least three top-level keys.
- Store an object as the value of each top-level key.
- Include
your_nameandyour_msginside each nested object. - Loop through all entries and print the key, name, and message.
- Skip any entry whose value is missing or null.
Keep learning
Related questions
Abort Ajax Requests with jQuery jqXHR.abort()
Learn how to cancel an in-progress jQuery Ajax request with jqXHR.abort(), handle abort status safely, and avoid stale UI updates.
Access the Correct this Inside a JavaScript Callback
Learn why JavaScript this changes in callbacks and how to preserve an object context using bind, arrow functions, and event handler patterns.
Add Key-Value Pairs to JavaScript Objects
Learn how to add key-value pairs to JavaScript objects with dot and bracket notation, dynamic keys, examples, and common mistakes.