Free lesson · JavaScript Basic to Advance
Iterating Over Objects
Looping Over an Object
Iterating over an object is more complicated than iterating over an array. Arrays have a natural order — first element, second element, and so on. Objects have keys and values, and the way you iterate depends on what you want — keys, values, or both.
JavaScript gives you three main tools:
Object.keys(obj)— an array of the object's own keysObject.values(obj)— an array of the object's own valuesObject.entries(obj)— an array of[key, value]pairs
const user = {
name: "Olena",
age: 35,
role: "Head of Product"
};
console.log(Object.keys(user)); // ["name", "age", "role"]
console.log(Object.values(user)); // ["Olena", 35, "Head of Product"]
console.log(Object.entries(user)); // [["name", "Olena"], ["age", 35], ["role", "Head of Product"]]
Each of these returns a regular array. Once you have an array, you can use all the array iteration methods we covered in Module 4 — forEach, map, filter, reduce, for...of.
Iterating Keys, Values, and Entries
Three common patterns, each using a different Object.* method:
Iterate keys:
const user = { name: "Olena", age: 35, role: "Head of Product" };
for (const key of Object.keys(user)) {
console.log(key);
}
Iterate values:
const user = { name: "Olena", age: 35, role: "Head of Product" };
for (const value of Object.values(user)) {
console.log(value);
}
Iterate entries (key and value together):
const user = { name: "Olena", age: 35, role: "Head of Product" };
for (const [key, value] of Object.entries(user)) {
console.log(`${key}: ${value}`);
}
The third one uses destructuring ([key, value]) to unpack each [key, value] array. This is the most common pattern when you need both pieces of information.
Interactive animation: The walk and the fold - entries destructured into [key, value] pairs, then values summed with reduce.
Transforming Objects
Combining Object.entries with array methods lets you transform objects functionally:
const user = { name: "olena", age: 35, role: "head of product" };
// Capitalize all string values
const capitalized = Object.fromEntries(
Object.entries(user).map(([key, value]) =>
[key, typeof value === "string" ? value.toUpperCase() : value]
)
);
console.log(capitalized);
The pattern: turn the object into entries, transform the entries with map or filter, then turn it back into an object with Object.fromEntries. This is the functional approach to "transform an object" — no mutation, returns a new object.
Filtering an object by its values:
const scores = { alice: 85, bob: 60, carol: 92, dave: 45 };
const passing = Object.fromEntries(
Object.entries(scores).filter(([key, value]) => value >= 70)
);
console.log(passing);
Same pattern: entries → filter → fromEntries. The result is a new object containing only the entries that passed the filter.
graph LR
A[Original Object] --> B[Object.entries<br/>turn into array of pairs]
B --> C[map / filter / reduce<br/>transform the array]
C --> D[Object.fromEntries<br/>turn back into object]
D --> E[New Object]
style B fill:#7c3aed,color:#fff
style D fill:#7c3aed,color:#fff
style E fill:#10b981,color:#fff
This diagram shows the pattern for functionally transforming an object. You start with the original object, convert it to an array of key-value pairs using Object.entries, use any array method like map, filter, or reduce to transform the array, then convert it back to an object using Object.fromEntries. The result is a new object with the transformations applied, without mutating the original.
This is the standard idiom for object transformation in modern JavaScript. Memorize it — you'll use it often.
Interactive animation: Filter an object like an array - out to entries, filtered as pairs, back with Object.fromEntries.
The for...in Loop
JavaScript has a for...in loop specifically for iterating over object keys:
const user = { name: "Olena", age: 35, role: "Head of Product" };
for (const key in user) {
console.log(`${key}: ${user[key]}`);
}
This works, and you'll see it in older codebases. But it has a subtle issue: for...in iterates over all enumerable properties, including those inherited from the prototype chain.
We cover prototypes in detail in Topic 7.5. The short version: every object inherits from another object (its prototype), and that prototype has properties too. for...in walks up the chain and includes inherited keys.
const proto = { inheritedKey: "from prototype" };
const user = Object.create(proto);
user.ownKey = "from user";
for (const key in user) {
console.log(key);
}
// Logs: ownKey, inheritedKey
// Compare with Object.keys
console.log(Object.keys(user)); // ["ownKey"] — only own keys
for...in shows both ownKey and inheritedKey. Object.keys shows only the own keys. For most modern code, Object.keys is what you want — you usually care about an object's own properties, not its inherited ones.
If you do use for...in and want to skip inherited properties, use Object.hasOwn to check:
const proto = { inheritedKey: "from prototype" };
const user = Object.create(proto);
user.ownKey = "from user";
for (const key in user) {
if (Object.hasOwn(user, key)) {
console.log(`Own: ${key}`);
} else {
console.log(`Inherited: ${key}`);
}
}
For most use cases in modern code, just use Object.keys, Object.values, or Object.entries. They give you only own properties and they work with array methods directly. for...in is mostly a legacy pattern at this point.
Interactive animation: for...in walks too far - it lists an inherited key that Object.keys leaves out.
Iteration Order
A question that comes up: in what order are object keys iterated?
For most cases in modern JavaScript, the answer is:
- Integer-like keys first, in ascending numeric order
- String keys next, in insertion order
- Symbol keys last, in insertion order
const obj = {
"z": 1,
"10": 2,
"a": 3,
"1": 4,
"5": 5
};
console.log(Object.keys(obj));
// ["1", "5", "10", "z", "a"]
// Integer-like first (in numeric order), then strings (in insertion order)
This is occasionally surprising. The integer-like keys come first regardless of their position in the object literal. This is a property of how JavaScript engines store objects internally, and it's been standardized since ES2015.
For most code, this doesn't matter — you shouldn't rely on iteration order in the first place. But if you find a bug where keys are coming out in an unexpected order, this is likely why. The fix is to use a Map instead of an object, since Map preserves strict insertion order regardless of key type.
Interactive animation: Integer-like keys jump the queue - ascending numbers first, then string keys in insertion order.
Counting Object Properties
A simple operation that's worth knowing: how to count the number of properties in an object.
const user = { name: "Olena", age: 35, role: "Head of Product" };
console.log(Object.keys(user).length); // 3
Object.keys(obj).length is the standard way. There's no built-in "size" property on regular objects (unlike Map and Set, which do have .size).
If you find yourself checking Object.keys(obj).length === 0 to test for "empty object," that's the standard pattern. Be aware that an empty object has no own keys but still inherits from the prototype chain.
Common Pitfalls
Warning: The iteration traps.
Using
for...inwithoutObject.hasOwn. Iterates over inherited properties, which is usually not what you want. PreferObject.keys,Object.values, orObject.entriesfor own-property iteration.Mutating the object while iterating. Adding or removing keys during iteration can produce inconsistent behavior depending on engine and iteration method. If you need to add or remove, collect changes first and apply them after the loop.
Assuming iteration order is undefined. It's actually well-specified: integer-like keys first in numeric order, then everything else in insertion order. If you need strict insertion order regardless of key type, use a
Map.
Why This Matters in Interviews
Interview: Object iteration questions appear constantly in coding problems. "Given an object, transform it into a new object where..." is a common pattern. Interviewers watch whether you reach for
Object.entries,Object.fromEntries, and array methods (modern style) or forfor...inwith manual property building (older style).The deeper question: "How would you count the keys of an object?" — the answer is
Object.keys(obj).length. If you don't know this off the top of your head, it signals limited JavaScript practice.Topic 7.8 — Interview Lens: Objects and Prototypes — covers the deeper interview treatment.
Try It
Exercise: Given this object:
const inventory = { apples: 12, bread: 3, coffee: 0, milk: 5, eggs: 0, cheese: 8 };Solve each problem using the most appropriate iteration tool:
- List only the names of items that are out of stock (count is 0)
- Calculate the total count of all items
- Build a new object containing only items with count >= 5
- Build a new object where each item's count is doubled
- Find the item with the highest count
Each one is solvable with
Object.entriesorObject.keyscombined with array methods. Try to write each as a single expression, no manual loops. By the end, you'll have internalized the "object → entries → transform → object" pattern.