Looping Through Objects in JavaScript: Complete Guide

Plain objects are not iterable with for...of, but JavaScript gives you three clean ways to loop through them. Learn Object.keys(), Object.values(), Object.entries(), and when for...in is the right choice.

6 min read

Unlike arrays, plain objects in JavaScript are not iterable. You cannot use for...of on an object directly. But JavaScript gives you several built-in methods that turn an object into something you can loop over.

The three main tools are Object.keys(), Object.values(), and Object.entries(). Each converts an object's properties into an array, which you can then iterate with for...of or any array method.

Object.keys(): Loop Over Property Names

Object.keys() returns an array of the object's own enumerable property names:

javascriptjavascript
const book = {
  title: "JavaScript: The Good Parts",
  author: "Douglas Crockford",
  year: 2008,
};
 
for (const key of Object.keys(book)) {
  console.log(`${key}: ${book[key]}`);
}

Output:

texttext
title: JavaScript: The Good Parts
author: Douglas Crockford
year: 2008

Object.keys() only returns the object's own properties, not inherited ones. This makes it safer than for...in for most use cases. The returned array works with any array method, not just loops:

javascriptjavascript
const keys = Object.keys(book);
console.log(keys); // ["title", "author", "year"]
console.log(keys.length); // 3
console.log(keys.includes("author")); // true

Object.values(): Loop Over Property Values

Object.values() returns an array of the object's own enumerable property values:

javascriptjavascript
const scores = {
  Alice: 92,
  Bob: 85,
  Carol: 78,
};
 
for (const score of Object.values(scores)) {
  console.log(score);
}
// Prints: 92, 85, 78

This is the cleanest option when you only care about the values and do not need the keys. Combined with array methods, it is powerful:

javascriptjavascript
const allScores = Object.values(scores);
const average = allScores.reduce((sum, s) => sum + s, 0) / allScores.length;
console.log(average); // 85

Object.entries(): Loop Over Key-Value Pairs

Object.entries() returns an array of [key, value] pairs. This is the most versatile option because you get both key and value in one call:

javascriptjavascript
const product = {
  name: "Laptop",
  price: 999,
  inStock: true,
};
 
for (const [key, value] of Object.entries(product)) {
  console.log(`${key} = ${value} (${typeof value})`);
}

Output:

texttext
name = Laptop (string)
price = 999 (number)
inStock = true (boolean)

Array destructuring in the loop header unpacks each pair into key and value. This pattern is the go-to for most object iteration in modern JavaScript because it is concise and gives you everything you need.

The Three Methods Compared

javascriptjavascript
const pet = { name: "Rex", species: "Dog", age: 4 };
MethodReturnsExample Output
Object.keys(pet)Array of keys["name", "species", "age"]
Object.values(pet)Array of values["Rex", "Dog", 4]
Object.entries(pet)Array of [key, value][["name","Rex"], ["species","Dog"], ["age",4]]
Object iteration method relationships

All three methods return arrays, which means you can use for...of, forEach, map, filter, reduce, or any array operation on the result.

for...in: The Lower-Level Alternative

for...in also iterates over object keys, but with one key difference: it includes inherited enumerable properties from the prototype chain:

javascriptjavascript
const base = { shared: true };
const derived = Object.create(base);
derived.own = "value";
 
// for...in sees both own and inherited
for (const key in derived) {
  console.log(key); // own, shared
}
 
// Object.keys only sees own properties
console.log(Object.keys(derived)); // ["own"]

For most everyday object iteration, Object.keys() with for...of is safer because it avoids prototype surprises. Use for...in when you genuinely need to see inherited properties or when debugging. For a full comparison, see the for...in guide.

Practical Patterns

Transforming an object

javascriptjavascript
const prices = { apple: 1.0, banana: 0.5, cherry: 2.0 };
 
const discounted = {};
for (const [fruit, price] of Object.entries(prices)) {
  discounted[fruit] = price * 0.8;
}
console.log(discounted);
// { apple: 0.8, banana: 0.4, cherry: 1.6 }

Filtering properties

javascriptjavascript
const user = { id: 1, name: "Alice", password: "secret", token: "abc123" };
 
const publicFields = {};
for (const [key, value] of Object.entries(user)) {
  if (key !== "password" && key !== "token") {
    publicFields[key] = value;
  }
}
console.log(publicFields); // { id: 1, name: "Alice" }

Building a query string

javascriptjavascript
const params = { search: "laptop", page: 1, sort: "price" };
 
const query = Object.entries(params)
  .map(([key, value]) => `${key}=${value}`)
  .join("&");
 
console.log(query); // "search=laptop&page=1&sort=price"

Counting occurrences

javascriptjavascript
const words = ["apple", "banana", "apple", "cherry", "banana", "apple"];
const counts = {};
 
for (const word of words) {
  counts[word] = (counts[word] || 0) + 1;
}
 
for (const [word, count] of Object.entries(counts)) {
  console.log(`${word}: ${count}`);
}
// apple: 3, banana: 2, cherry: 1

Choosing the Right Tool

SituationBest Choice
Need both key and valueObject.entries()
Need only keysObject.keys()
Need only valuesObject.values()
Need inherited propertiesfor...in
Need array methods (map, filter)Object.entries() + array method
Quick debug dumpconsole.log(obj) or Object.entries()

For array iteration, see the array looping guide and the for...of guide. For choosing between for, for...of, and forEach across data types, see the loop comparison guide.

Rune AI

Rune AI

Key Insights

  • Plain objects are not iterable; use Object.keys/values/entries or for...in.
  • Object.keys(obj) returns an array of the object's own property names.
  • Object.values(obj) returns an array of the object's own property values.
  • Object.entries(obj) returns an array of [key, value] pairs.
  • for...in includes inherited properties; use hasOwnProperty() to filter them.
RunePowered by Rune AI

Frequently Asked Questions

Why can't I use for...of on a plain object?

Plain objects are not iterable by default. They lack the Symbol.iterator method that for...of requires. Use Object.keys(), Object.values(), Object.entries(), or for...in instead.

Does Object.keys() guarantee the same order as for...in?

Object.keys() returns own enumerable properties in the same order as for...in would iterate them, but without inherited properties. For string keys, the order matches insertion except for integer-like keys, which come first in numeric order.

Which method should I use as a default for object iteration?

Object.entries() is the most versatile because it gives you both key and value in one call. If you only need keys, use Object.keys(). If you only need values, use Object.values().

Conclusion

Plain objects need a different approach than arrays for iteration. Object.keys(), Object.values(), and Object.entries() convert an object into an array you can loop over with for...of, giving you clean syntax and avoiding prototype chain surprises. for...in is the lower-level alternative when you need to include inherited properties or work in older environments.