Object.keys, Object.values, and Object.entries: How to Choose
Object.keys, Object.values, and Object.entries are not three versions of the same idea. They answer three different questions. Choose Object.keys when the property names are the data, Object.values when the stored values are the data, and Object.entries when the relationship between the name and value matters.
That small decision prevents a lot of awkward code. If you start with the wrong object method, the rest of the chain usually spends its time rebuilding information you threw away too early.
Table of contents
- The decision model
- Use Object.keys when you need property names
- Use Object.values when you need the data
- Use Object.entries when you need both
- Use Object.fromEntries for the return trip
- Common pitfalls
- How this connects to practice
- Key Takeaways
The decision model
Objects store values under names:
const scores = {
ada: 92,
grace: 88,
linus: 71,
};
Before choosing a method, ask what each item in the next step should contain.
| Need | Use | Result shape |
|---|---|---|
| Property names | Object.keys(scores) | ["ada", "grace", "linus"] |
| Stored values | Object.values(scores) | [92, 88, 71] |
| Names and values together | Object.entries(scores) | [["ada", 92], ["grace", 88], ["linus", 71]] |
| Object rebuilt from pairs | Object.fromEntries(pairs) | { ada: 92, grace: 88, linus: 71 } |
The method is not the interesting part. The output shape is.
Use Object.keys when you need property names
Use Object.keys when the property names are what you want to inspect, display, count, or validate.
const preferences = {
darkMode: true,
emailUpdates: false,
autoSave: true,
};
const settingNames = Object.keys(preferences);
console.log(settingNames);
// ["darkMode", "emailUpdates", "autoSave"]
This is the right tool when your condition is about the names:
const hasPrivateSetting = Object.keys(preferences).some((name) => {
return name.startsWith("_");
});
The values do not matter there. You are asking a question about labels.
A common mistake is using Object.keys and then immediately indexing back into the object because you actually needed values:
const prices = {
keyboard: 49,
mouse: 29,
monitor: 199,
};
const total = Object.keys(prices).reduce((total, itemName) => {
return total + prices[itemName];
}, 0);
That works, but it is a clue. If the key is only being used to fetch the value, start with the values instead.
Use Object.values when you need the data
Use Object.values when the stored values are the data and the property names are just labels.
const prices = {
keyboard: 49,
mouse: 29,
monitor: 199,
};
const total = Object.values(prices).reduce((total, price) => {
return total + price;
}, 0);
console.log(total); // 277
This reads like the task: get the prices, then total them.
Object.values is also the right fit for value-only filtering:
const stock = {
apples: 42,
bananas: 0,
cherries: 15,
dates: 0,
};
const outOfStockCount = Object.values(stock).filter((quantity) => {
return quantity === 0;
}).length;
console.log(outOfStockCount); // 2
The item names do not affect the result. Throwing them away is fine.
The trap is throwing them away before you discover you still need them:
const menu = {
espresso: 3,
latte: 4.5,
cappuccino: 4,
};
const lines = Object.values(menu).map((price) => {
return `$${price}`;
});
console.log(lines);
// ["$3", "$4.5", "$4"]
That cannot produce "espresso - $3" because the names are already gone. Use entries when the output needs both sides.
Use Object.entries when you need both
Use Object.entries when each step needs the property name and its value together.
const menu = {
espresso: 3,
latte: 4.5,
cappuccino: 4,
};
const lines = Object.entries(menu).map(([item, price]) => {
return `${item} - $${price}`;
});
console.log(lines);
// ["espresso - $3", "latte - $4.5", "cappuccino - $4"]
Each entry is a two-item array. Destructuring makes the pair readable:
for (const [item, price] of Object.entries(menu)) {
console.log(`${item}: ${price}`);
}
Object.entries is especially useful when you need to filter by one side and keep the other side:
const scores = {
ada: 92,
grace: 88,
linus: 71,
brendan: 64,
};
const passingEntries = Object.entries(scores).filter(([name, score]) => {
return score >= 80;
});
console.log(passingEntries);
// [["ada", 92], ["grace", 88]]
The callback receives both name and score. You may not need the name in the condition, but keeping it in the pair means the result still knows which score belongs to which person.
This is also the shape you want for query strings, logs, audit tables, config cleanup, and any transformation where the key is meaningful data.
Use Object.fromEntries for the return trip
Object.entries turns an object into pairs. Object.fromEntries turns pairs back into an object.
const pairs = [
["theme", "dark"],
["pageSize", 25],
];
const settings = Object.fromEntries(pairs);
console.log(settings);
// { theme: "dark", pageSize: 25 }
The full round trip is:
object -> entries -> array methods -> fromEntries -> object
That is the standard pattern when you want to transform or filter an object while keeping an object as the result:
const stock = {
apples: 42,
bananas: 0,
cherries: 15,
dates: 0,
};
const inStock = Object.fromEntries(
Object.entries(stock).filter(([item, quantity]) => {
return quantity > 0;
}),
);
console.log(inStock);
// { apples: 42, cherries: 15 }
You can also map entries to update values while preserving keys:
const prices = {
keyboard: 100,
mouse: 50,
monitor: 200,
};
const discounted = Object.fromEntries(
Object.entries(prices).map(([item, price]) => {
return [item, price * 0.9];
}),
);
console.log(discounted);
// { keyboard: 90, mouse: 45, monitor: 180 }
This is where Object.entries earns its keep. You can reshape pairs with normal array methods, then return to object form without manually assigning properties one at a time.
Common pitfalls
Plain objects are not arrays
You cannot call array methods directly on a plain object:
const scores = {
ada: 92,
grace: 88,
};
scores.map((score) => score * 2);
// TypeError: scores.map is not a function
Convert first:
const doubledScores = Object.values(scores).map((score) => {
return score * 2;
});
The Working with Data Object Methods lesson teaches this bridge directly: object methods produce arrays, then array methods can take over.
Do not use Object.values when the key is part of the answer
This cannot build useful query-string pairs:
const params = {
page: 2,
q: "objects",
archived: false,
};
const query = Object.values(params).join("&");
console.log(query);
// "2&objects&false"
The keys were the parameter names. Once they are gone, the string has values but no meaning.
Use entries:
const query = Object.entries(params)
.map(([key, value]) => `${key}=${value}`)
.join("&");
console.log(query);
// "page=2&q=objects&archived=false"
Real query-string code should also handle encoding and skipped values, but the object-method choice is the same: you need keys and values together.
Empty objects return empty arrays
All three extraction methods handle empty objects cleanly:
console.log(Object.keys({})); // []
console.log(Object.values({})); // []
console.log(Object.entries({})); // []
That makes them friendly with array methods:
const total = Object.values({}).reduce((total, value) => {
return total + value;
}, 0);
console.log(total); // 0
The initial value on reduce still matters. Without it, reducing an empty array throws.
The methods read own enumerable string-keyed properties
For normal object literals, this is exactly what you expect:
const user = {
name: "Ada",
role: "admin",
};
console.log(Object.keys(user)); // ["name", "role"]
Inherited properties are not included:
const user = Object.create({ inheritedRole: "admin" });
user.name = "Ada";
console.log(Object.keys(user)); // ["name"]
That is usually a feature. When you inspect plain data objects, you normally want the object's own data, not properties from its prototype chain.
Numeric-looking keys have special ordering rules
Property order is predictable, but it is not always insertion order for every key. Integer-like keys come first in ascending numeric order, followed by other string keys in insertion order.
const weird = {
zebra: true,
2: "two",
1: "one",
alpha: true,
};
console.log(Object.keys(weird));
// ["1", "2", "zebra", "alpha"]
Do not model ordered lists as objects and then hope property order will save the day. Use an array when order is the main idea.
How this connects to practice
For guided lesson practice, start with Working with Data: Object Methods. It walks through Object.keys, Object.values, Object.entries, Object.fromEntries, and object spread as one workflow.
Then try these exercises:
- Object Keys and Values for deciding between names and values
- Object.entries for turning object pairs into a query string
- Reduce Into an Object for building an object summary from array data
For related reading, use JavaScript Spread Operator when you are copying or merging object data, and JavaScript reduce Accumulator Patterns for Real Data when the final result should be a count, lookup, group, or summary object.
Key Takeaways
- Use
Object.keyswhen the property names are the data you need to inspect, validate, or display. - Use
Object.valueswhen only the stored values matter and losing the names is harmless. - Use
Object.entrieswhen the key and value belong together in the next step. - Use
Object.fromEntriesafter filtering or mapping entries when the final answer should be an object again. - Choose by output shape first. The clean method usually becomes obvious after that.