Object.keys, values & entries
Turn JavaScript objects into arrays, transform their keys and values, and rebuild new objects with Object.fromEntries.
- 01Choose the right listUse Object.keys, Object.values, or Object.entries for the job in front of you.
- 02Round-trip objectsUnpack an object into pairs, transform the pairs, and repack them with Object.fromEntries.
- 03Avoid enumeration surprisesKnow what own, enumerable, string keys means, and why inherited and symbol keys are skipped.
Objects become easier when they can become lists
Objects are excellent when you know the property name you want: read user.name, update cart.total, call account.save(). But many data tasks ask a different question: what are all the properties? How many are there? What are all the prices? Can we rename every field and make a new object?
That is where Object.keys, Object.values, and Object.entries come in. They turn an object into arrays. Once your data is an array, you can loop with for…of, count with .length, and, with a tiny preview of next module, transform with .map and .filter.
Imagine a cabinet full of drawers. Sometimes you want the labels: “notebook,” “pencil,” “backpack.” Sometimes you want the contents: 12, 2, 45. Sometimes you need both together because you are moving house and every box needs a label and contents. Objects work the same way.
- In real life: Drawer labels
- In JavaScript:
Object.keys(obj)returns property names - In real life: Drawer contents
- In JavaScript:
Object.values(obj)returns values - In real life: A packing list: label + contents
- In JavaScript:
Object.entries(obj)returns[key, value]pairs - In real life: Unpacking into a new cabinet
- In JavaScript:
Object.fromEntries(pairs)rebuilds an object
Where the analogy stops: A real cabinet can have duplicate drawer labels. A JavaScript object cannot: if the same key is written twice, the later value overwrites the earlier one.
Object.keys, Object.values, and Object.entries read the same visible own string properties of an object, but return names, values, or pairs. Object.fromEntries does the reverse: pairs back to an object.
The previous for…of & for…in lesson introduced looping and mentioned that for…in includes inherited keys. This lesson gives you the safer everyday object tools: they ignore inherited keys, which is usually exactly what you want when transforming data.
Object.keys, values & entries
STEP THROUGHStart with a small object and ask three questions. What are its property names? What values are stored there? What pairs keep each name next to its value?
const user = { name: "Ada", role: "admin" };
Object.keys(user); // ["name", "role"]
Object.values(user); // ["Ada", "admin"]
Object.entries(user); // [["name", "Ada"], ["role", "admin"]]The three methods do not mean “every possible property.” They mean: own, enumerable, string-keyed properties. Own means directly on this object, not inherited. Enumerable means intended to show up in ordinary listings. String keyed means symbol keys are skipped. The Symbols lesson comes next; this is your first tease.
Predict what will be skipped. Then step through the real lists JavaScript creates.
script
const cabinet = Object.create({ inherited: "from prototype" });cabinet.name = "Ada";cabinet.role = "developer";// no integer-like key yetcabinet[secret] = "hidden";Object.defineProperty(cabinet, "quiet", { value: "non-enumerable", enumerable: false,});console.log(Object.keys(cabinet));console.log(Object.values(cabinet));console.log(Object.entries(cabinet));Turn on the numeric key in the player. You will see a professional edge case: integer-like property names, such as "2", list before other string keys. After those integer-like names, ordinary string keys keep insertion order.
“Own” means the drawer belongs to this cabinet, not to a cabinet it borrows from. “Enumerable” means “show this in ordinary lists.” Most properties you write with object literal syntax are enumerable. Some built-ins and properties created with Object.defineProperty are not.
Object.fromEntries: arrays of pairs back to objects
STEP THROUGHIf Object.entries is packing an object into labeled boxes, Object.fromEntries is unpacking the boxes into a new cabinet. The input must produce two-item pairs: key first, value second.
Watch a list of pairs become an object. Duplicate keys keep the last value.
script
["admin", "Ada"], ["editor", "Lin"], ["admin", "Grace"],];const lookup = Object.fromEntries(pairs);console.log(lookup);Duplicate keys are not an error. Objects can hold only one value for a key, so the later pair wins. That rule matters when you build lookup objects and when you invert objects later in this lesson.
Object.fromEntries([["theme", "dark"], ["font", "large"]]);
Object.fromEntries(new Map([["id", 42], ["name", "Ada"]]));
Object.fromEntries(new URLSearchParams("page=1&sort=new"));The second and third lines are teasers. Map & Set and URL & URLSearchParams have their own lessons later. The important idea now: Object.fromEntries is happy with anything that yields pairs.
Transforming objects with map
INTERACTIVEObjects do not have an obj.map(...) method. Arrays do. So the pattern is a round trip: unpack → change → repack.
When you move house, you do not magically transform the cabinet. You empty it into labeled boxes, change the labels or contents you need to change, then unpack into the new place. Transforming an object works the same way.
- In real life: Pack every drawer into labeled boxes
- In JavaScript:
Object.entries(prices) - In real life: Change every price tag or discard expensive boxes
- In JavaScript:
.map(...)and.filter(...) - In real life: Unpack into a fresh cabinet
- In JavaScript:
Object.fromEntries(...)
Where the analogy stops: Moving boxes can hold anything. Object keys are property keys; if two transformed pairs get the same key, the later one overwrites the earlier one.
const prices = { notebook: 12, pencil: 2, backpack: 45 };const discounted = Object.fromEntries( Object.entries(prices) .map(([item, price]) => [item, price * 0.8]) .filter(([item, price]) => price <= 20));console.log(discounted);{"notebook":12,"pencil":2,"backpack":45}[["notebook",12],["pencil",2],["backpack",45]][["notebook",9.6],["pencil",1.6],["backpack",36]][["notebook",9.6],["pencil",1.6]]{"notebook":9.6,"pencil":1.6}Discount 20% first, then keep items at $20 or less. 2 items remain after filter, and Object.fromEntries repacks them.
This playground previews map and filter before their full array-methods lesson next module. Here is all you need: map makes one changed item for every old item, while filter keeps only items that pass a test. With entries, the “item” is a [key, value] pair.
Where you will use this
The round trip shows up anywhere object-shaped data needs a small rewrite before display, saving, or sending elsewhere.
Rename keys and change values together
const user = { first_name: "Ada", last_name: "Lovelace" };
const renamed = Object.fromEntries(
Object.entries(user).map(([key, value]) => [
key.replace("_", ""),
value.toUpperCase(),
])
);
console.log(renamed);Gentle destructuring appears in the callback: ([key, value]) names the two items in each entry pair. The Destructuring lesson later gives this syntax a full tour.
Pick, omit, and invert
function pick(obj, keys) {
return Object.fromEntries(
Object.entries(obj).filter(([key]) => keys.includes(key))
);
}
function omit(obj, keys) {
return Object.fromEntries(
Object.entries(obj).filter(([key]) => !keys.includes(key))
);
}
function invert(obj) {
return Object.fromEntries(
Object.entries(obj).map(([key, value]) => [value, key])
);
}pick keeps allowed fields, such as safe profile data. omit removes fields, such as a password before display. invert builds reverse lookups, but duplicate values overwrite because object keys must be unique.
Count, check empty, and sum values
const scores = { Ada: 9, Lin: 7, Grace: 10 };
console.log(Object.keys(scores).length);
console.log(Object.values(scores).reduce((sum, score) => sum + score, 0));
console.log(Object.keys({}).length === 0);Object.keys(obj).length is the common empty-object check for ordinary data objects: Object.keys(obj).length === 0. For sums, Object.values(scores) gives you the numbers. The code above uses reduce lightly; a for…of loop over the values would be just as clear at this stage.
Choosing the right tool
SORTER| Tool | Includes | Returns | Typical use |
|---|---|---|---|
for…in | Enumerable string keys, including inherited ones | Key strings one at a time | Walking legacy objects when you intentionally want inherited enumerable keys |
Object.keys(obj) | Own enumerable string keys | An array of keys | Counting properties, checking emptiness, rendering labels |
Object.values(obj) | Values at own enumerable string keys | An array of values | Summing scores, checking all statuses |
Object.entries(obj) | Own enumerable string key/value pairs | An array of [key, value] pairs | Transforming, filtering, renaming, rebuilding |
Use this quick test: do you need labels, contents, or labels and contents together?
- Count how many settings an object has
- Add all the numbers in a scores object
- Rename
first_nametofirstNamewhile keeping its value - Render a list of field names in a form
- Find the average of every price
- Keep only items whose value is under 20 and rebuild an object
Sort each task by the method that gives the most useful starting array.
Common misconceptions
“Object.keys is the same as for…in.”
for…in can include inherited enumerable keys. Object.keys returns an array of own enumerable string keys only.
“These methods include symbol keys.”
They skip symbols. That is why the next lesson, Symbols, matters. Use tools such as Object.getOwnPropertySymbols or Reflect.ownKeys later when you intentionally need symbols.
“Property order is always insertion order.”
Integer-like keys come first in ascending order. Other string keys then follow insertion order. The step-through experiment proves it.
“Object.fromEntries preserves duplicate keys somehow.”
It cannot. Plain objects have one slot per property key. Later pairs overwrite earlier pairs with the same key.
“The round trip changes the original object.”
The usual entries → map/filter → fromEntries pattern creates a new object. It does not mutate the original unless your callback does extra mutation itself.
Practice: object lists and round trips
5 EXERCISESPredict what the program prints.
const pet = { name: "Miso", kind: "cat", age: 4 };
console.log(Object.keys(pet).length);Object.keys(pet) is ["name", "kind", "age"], so its length is 3.
Use entries, map, and fromEntries to create a new object with every price doubled.
const prices = { apple: 2, bread: 3 };
const doubled = Object.fromEntries(
Object.entries(prices).map(([item, price]) => [item, price * 2])
);
console.log(doubled);const prices = { apple: 2, bread: 3 };
const doubled = Object.fromEntries(
Object.entries(prices).map(([item, price]) => [item, price * 2])
);
console.log(doubled);Entries keeps each item name next to its price. map doubles each price, and Object.fromEntries rebuilds { apple: 4, bread: 6 }.
Write a pick function that keeps only the named keys.
function pick(obj, keys) {
// return a new object with only the listed keys
}
const user = { id: 1, name: "Ada", admin: true };
console.log(pick(user, ["id", "name"]));function pick(obj, keys) {
return Object.fromEntries(
Object.entries(obj).filter(([key]) => keys.includes(key))
);
}Filtering entries keeps the key and value together. fromEntries turns the remaining pairs back into an object.
Predict the boolean printed by the program.
const cart = {};
console.log(Object.keys(cart).length === 0);Object.keys(cart) is [], and [].length === 0 is true.
Invert the small lookup and predict which old key survives for the duplicate value D.
const codes = { draft: "D", published: "P", archived: "D" };
console.log(Object.fromEntries(
Object.entries(codes).map(([key, value]) => [value, key])
));The inverted pairs are ["D", "draft"], ["P", "published"], and ["D", "archived"]. The last D overwrites the first, so D maps to archived.
Quiz: check your understanding
7 QUESTIONSAnswer once from your prediction, then read every explanation.
Question 1 of 7Which method returns an array of property names?
Choose an answer to see the explanation.
Question 2 of 7What does Object.values print here?
Read the code, then predictconst user = { name: "Ada", role: "admin" }; console.log(Object.values(user));Choose an answer to see the explanation.
Question 3 of 7What does Object.entries print here?
Read the code, then predictconst score = { Ada: 9 }; console.log(Object.entries(score));Choose an answer to see the explanation.
Question 4 of 7Which properties do Object.keys, values, and entries include?
Choose an answer to see the explanation.
Question 5 of 7What does Object.fromEntries print with duplicate pairs?
Read the code, then predictconst pairs = [["a", 1], ["a", 2]]; console.log(Object.fromEntries(pairs));Choose an answer to see the explanation.
Question 6 of 7What order does Object.keys print for integer-like keys?
Read the code, then predictconst obj = { 2: "two", name: "Ada", 1: "one" }; console.log(Object.keys(obj));Choose an answer to see the explanation.
Question 7 of 7Which round trip transforms an object without mutating the original?
Choose an answer to see the explanation.
Key takeaways
Object.keys(obj)returns own enumerable string keys.Object.values(obj)returns the values at those same keys, in the same order.Object.entries(obj)returns[key, value]pairs, the best shape for transformation.Object.fromEntries(pairs)rebuilds a new object; duplicate keys keep the last value.- For object transformations, use the round trip: entries → map/filter → fromEntries.
Remember the one-liner.
Turn objects into arrays when you need array tools; turn pairs back into objects when you are done.
Up next: Symbols.