Complete JavaScript Course Module 7: Intermediate: Objects and JSON

Looping Over Arrays and Objects: for...of, for...in and Object.entries

  • Beginner
  • Lesson 7.4
  • 5 min read
  • 30 of 76 in the course

In short

Learn the best ways to loop over arrays and objects in JavaScript with for...of, Object.keys, Object.values and Object.entries, plus optional chaining for safe access. How to loop over an array with for...of The for...of loop goes through each value of an array, one by one, without a counter.

Learn the best ways to loop over arrays and objects in JavaScript with for...of, Object.keys, Object.values and Object.entries, plus optional chaining for safe access.

How to loop over an array with for...of

The for...of loop goes through each value of an array, one by one, without a counter. It reads almost like English: "for each item of the list, do this".

const songs = ["Intro", "Sunrise", "Night Drive"];

for (const song of songs) {
  console.log(`Now playing: ${song}`);
}
// Output:
// Now playing: Intro
// Now playing: Sunrise
// Now playing: Night Drive

for (const letter of "Hey") {
  console.log(letter);
}
// Output:
// H
// e
// y

Each time through the loop, song holds the next value. You can use const because a fresh variable is created for every round. for...of also works on strings, giving you one character at a time.

Unlike forEach, you can stop a for...of loop early with break, or skip a round with continue.

If you also need the index, use the entries() method of arrays together with destructuring:

const steps = ["Preheat oven", "Mix flour", "Bake 20 min"];

for (const [index, step] of steps.entries()) {
  console.log(`Step ${index + 1}: ${step}`);
}
// Output:
// Step 1: Preheat oven
// Step 2: Mix flour
// Step 3: Bake 20 min

steps.entries() gives pairs like [0, "Preheat oven"], and [index, step] unpacks each pair.

Why you should not use for...in on arrays

JavaScript also has a for...in loop. It loops over the keys (property names) of an object, not the values. On an array, those keys are index strings like "0", "1", "2".

const colors = ["red", "green"];

for (const key in colors) {
  console.log(key, typeof key);
}
// Output:
// 0 string
// 1 string

This causes problems: the index is a string, so key + 1 gives "01", not 1. for...in can also pick up extra properties that were added to the array. For arrays, always use for...of, a classic for loop, or array methods like forEach.

Common mistake: Mixing up of and in. Remember: for...of gives you the values of an array. for...in gives you the keys in an object. For objects, the Object methods below are usually clearer anyway.

How to loop over an object with Object.keys, Object.values and Object.entries

Plain objects do not work with for...of directly. Instead, you turn the object into an array first, using one of three built-in helpers:

MethodReturnsExample result
Object.keys(obj)Array of keys["html", "css"]
Object.values(obj)Array of values[90, 75]
Object.entries(obj)Array of [key, value] pairs[["html", 90], ["css", 75]]

Because these return arrays, you can loop over them with for...of or use any array method.

const scores = { html: 90, css: 75, javascript: 82 };

console.log(Object.keys(scores));
// Output: ["html", "css", "javascript"]

const total = Object.values(scores).reduce((sum, s) => sum + s, 0);
console.log(`Average: ${total / Object.keys(scores).length}`);
// Output: Average: 82.33333333333333

for (const [subject, score] of Object.entries(scores)) {
  const result = score >= 80 ? "pass with merit" : "pass";
  console.log(`${subject}: ${score} (${result})`);
}
// Output:
// html: 90 (pass with merit)
// css: 75 (pass)
// javascript: 82 (pass with merit)

The last loop is the pattern you will use most: Object.entries gives pairs, and [subject, score] destructures each pair into two clear variable names.

Tip: To round the average for display, use (total / 3).toFixed(1), which gives the string "82.3".

Looping over an array of objects

Real data often comes as an array of objects. Combine for...of with object destructuring to keep the loop short:

const team = [
  { name: "Ada", role: "Developer" },
  { name: "Ben", role: "Designer" },
];

for (const { name, role } of team) {
  console.log(`${name} works as a ${role}.`);
}
// Output:
// Ada works as a Developer.
// Ben works as a Designer.

Optional chaining: safe access with ?.

When data is nested, some parts may be missing. Reading a property of undefined throws an error and stops your script. Optional chaining ?. checks first: if the value on the left is null or undefined, it stops and returns undefined instead of crashing.

const users = [
  { name: "Mo", address: { city: "Cairo" } },
  { name: "Lea" },
];

for (const user of users) {
  // user.address.city would crash for Lea
  const city = user.address?.city ?? "Unknown city";
  console.log(`${user.name}: ${city}`);
}
// Output:
// Mo: Cairo
// Lea: Unknown city

user.address?.city returns undefined for Lea because she has no address. The ?? operator (called nullish coalescing) then gives a fallback value when the left side is null or undefined. You can also use ?. with methods, like user.getName?.(), and with brackets, like order.items?.[0].

Note: Use ?. only where data is truly allowed to be missing. If a value should always exist, a crash helps you find the bug faster. See MDN on optional chaining for more.

Practice exercise

Create an object inventory where keys are fruit names and values are quantities, such as { apples: 12, bananas: 0, kiwis: 5 }.

  1. Use Object.entries and for...of to log lines like "apples: 12 in stock".
  2. Log "Sold out!" instead for any fruit with quantity 0.
  3. Use Object.values to log the total number of fruits.
  4. Write a line using ?. and ?? that safely reads inventory.extras?.bags and falls back to 0.

Hint: Destructure with const [fruit, qty] of Object.entries(inventory) and use an if for the sold-out case.

Key takeaways

  • for...of loops over values of arrays and strings, and supports break and continue.
  • Avoid for...in on arrays; its keys are strings and it can include extra properties.
  • Object.keys, Object.values and Object.entries turn objects into arrays you can loop over.
  • Destructuring inside loops ([key, value] or { name, role }) keeps code readable.
  • Optional chaining ?. safely reads nested data, and ?? provides a fallback value.