Object.keys, values & entries
Turn JavaScript objects into arrays, transform their keys and values, and rebuild new objects with Object.fromEntries.
- 01Choose the right listPick
Object.keysfor the names,Object.valuesfor the values, orObject.entriesfor both together. - 02Change an object in three stepsTurn an object into pairs, change the pairs, and build a new object with
Object.fromEntries. - 03Know what gets skippedExplain why borrowed keys, symbol keys, and hidden keys don't show up, and why number-like keys come first.
Turn an object into lists
An object is good when you know the name you want. You write user.name to read a name. You write cart.total = 10 to change a total.
Some jobs ask a different question. They need all of an object's properties at once. A property is one named value inside an object. Its name is called the key. Here are some jobs like that:
- How many properties does this object have?
- What are all the prices in it?
- Can I rename every key and make a new object?
Three built-in tools help: Object.keys, Object.values, and Object.entries. Each one turns an object into an array, an ordered list. With an array, you can loop with for…of and count with .length. You can also use .map and .filter, two array tools you'll meet briefly in this lesson.
Picture a cabinet with drawers. Each drawer has a label, like "notebook" or "pencil". Inside each drawer is a price, like 12 or 2. Sometimes you want only the labels. Sometimes you want only the prices. When you move house, you write a packing list: each label next to what is inside.
- In real life: The drawer labels
- In JavaScript:
Object.keys(obj)gives the property names - In real life: What is inside each drawer
- In JavaScript:
Object.values(obj)gives the values - In real life: A packing list: each label with what is inside
- In JavaScript:
Object.entries(obj)gives[key, value]pairs - In real life: Unpacking the list into a new cabinet
- In JavaScript:
Object.fromEntries(pairs)builds a new object
Object.keys, Object.values, and Object.entries all look at the same properties of an object. They give back different arrays: the names, the values, or [name, value] pairs. Object.fromEntries goes the other way. It turns pairs back into an object.
In the for…of & for…in lesson, you saw that for…in also visits keys that an object borrows from a parent object. The tools in this lesson skip those borrowed keys. Most of the time, that is what you want when you change data.
Object.keys, values & entries
STEP THROUGHStart with a small object. Ask it three questions:
- What are its property names?
- What values does it hold?
- Which value goes with which name?
const user = { name: "Ada", role: "admin" };
console.log(Object.keys(user));
console.log(Object.values(user));
console.log(Object.entries(user));- Line 1 makes a
userobject with two properties:nameandrole. - Line 2 prints the names:
["name", "role"]. - Line 3 prints the values:
["Ada", "admin"]. - Line 4 prints the pairs:
[["name", "Ada"], ["role", "admin"]]. Each pair is a small array. The name comes first and the value second.
Each call makes a new array. If you change the object later, the array does not change with it.
Object.keys gives the names. Object.values gives the values. Object.entries gives pairs, and each pair is a small array: [name, value].These methods don't list every property. They list a property only when all three of these are true:
- It is own: it is stored on this object itself. A property the object borrows from a parent object is not own. (In JavaScript, that parent object is called the prototype.)
- It is enumerable: a hidden yes-or-no setting on the property says "show me in lists".
- It has a string key: its name is text. A key can also be a symbol, a special kind of key that is not text. The Symbols lesson comes next.
The step-through below builds an object with all four kinds of property. Then it lists them. The code uses three tools you may not know yet:
Symbol("secret")makes a new symbol to use as a key.Object.create(parent)makes a new, empty object that borrows fromparent.Object.definePropertyadds a property with its settings. Here it setsenumerable: false.
Guess which properties will be skipped. Then step through and see the real lists.
script
const cabinet = Object.create({ inherited: "from prototype" });cabinet.name = "Ada";cabinet.role = "developer";// no whole-number 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));Now pick "Add key 2" in the step-through. Line 5 then adds a property whose key is "2". Keys like this, that look like whole numbers, have a special order rule:
- Keys that look like whole numbers come first, from smallest to largest.
- All other string keys come next, in the order you added them.
"Own" means the property is stored on this object, not borrowed from its parent object. "Enumerable" means the property may show up in lists. A property you write inside { } is enumerable. Some built-in properties are not. Properties made with Object.defineProperty are not, unless you say enumerable: true.
These methods only look at the first level. Sometimes a value is another object. Then Object.values gives you that whole inner object. It does not look inside it.
const user = { profile: { city: "Pune" }, active: true };
console.log(Object.values(user));Line 1 makes a user with two properties. The profile property holds another object, { city: "Pune" }. Line 2 prints [{ city: "Pune" }, true]. The inner object comes back whole. You don't get "Pune" on its own. To work with the city, first pick the level you want, for example Object.values(user.profile).
Object.fromEntries: from pairs back to an object
STEP THROUGHObject.entries turns an object into pairs. Object.fromEntries does the opposite. It takes a list of pairs and builds a new object. Each pair must have two parts: the key first, then the value.
const settings = Object.fromEntries([
["theme", "dark"],
["fontSize", 16],
]);
console.log(settings);Lines 1 to 4 pass an array of two pairs to Object.fromEntries. The first pair makes the key theme with the value "dark". The second makes fontSize with the value 16. Line 5 prints { theme: "dark", fontSize: 16 }.
What if the same key appears twice? Step through the next example and see.
Watch a list of pairs become an object. When a key repeats, the last value wins.
script
["admin", "Ada"], ["editor", "Lin"], ["admin", "Grace"],];const lookup = Object.fromEntries(pairs);console.log(lookup);A repeated key does not cause an error. But an object can hold only one value for each key. So the later pair replaces the earlier one. You'll use this rule again when you swap keys and values later in this lesson.
Object.fromEntries makes one property from each pair. The key admin appears twice, but an object has only one admin, so the later pair replaces the earlier one.Each item you give to Object.fromEntries must hold a key and a value. Keep both parts when you change the pairs. If your code gives back only the value, Object.fromEntries can't know which key to use.
Pairs don't have to come from an array. The next example uses two tools that have their own lessons later:
- A Map is a collection of key-value pairs.
- URLSearchParams reads the part of a web address after the
?, likepage=1&sort=new.
const fromArray = Object.fromEntries([["id", 42]]);
const fromMap = Object.fromEntries(new Map([["name", "Ada"]]));
const fromUrl = Object.fromEntries(new URLSearchParams("page=1&sort=new"));
console.log(fromArray);
console.log(fromMap);
console.log(fromUrl);- Line 1 builds an object from an array with one pair. Line 4 prints
{ id: 42 }. - Line 2 builds an object from a
Map. Line 5 prints{ name: "Ada" }. - Line 3 builds an object from the text
page=1&sort=new. Line 6 prints{ page: "1", sort: "new" }.
Object.fromEntries works with anything that gives it pairs, one after another.
Transforming objects with map
INTERACTIVEArrays have a .map method. Objects don't: there is no obj.map(...). So to change every property of an object, you make a round trip in three steps:
- Turn the object into pairs with
Object.entries. - Change the pairs with array tools.
- Build a new object from the changed pairs with
Object.fromEntries.
Two array tools do the changing. They have a full lesson in the next module. For now, this is all you need:
.map(fn)makes a new array. It callsfnon each item and keeps whatfngives back..filter(fn)makes a new array with only the items wherefngives backtrue.
Here each item is a [key, value] pair. Writing ([item, price]) => gives the two parts of the pair their own names, item and price. This is called destructuring, and it has its own lesson later.
map, but arrays do. So you turn the object into pairs, change each pair with map, and build a new object from the changed pairs. The first object stays the same.When you move house, you can't change the cabinet in one go. You pack each drawer into a labeled box. You change the boxes you need to change. Then you unpack into the new cabinet.
- In real life: Pack every drawer into labeled boxes
- In JavaScript:
Object.entries(prices) - In real life: Change some price tags, or leave expensive boxes behind
- In JavaScript:
.map(...)and.filter(...) - In real life: Unpack into a new cabinet
- In JavaScript:
Object.fromEntries(...)
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}Take 20% off every price, then keep the items that cost $20 or less. 2 items are left, and Object.fromEntries builds a new object from them.
The code takes 20% off every price, then keeps only prices of 20 or less:
- Line 1 makes a
pricesobject with three items. - Line 3 turns it into pairs, like
["notebook", 12]. - Line 4 makes a new pair for each old pair: the same item name, and the price times 0.8.
- Line 5 keeps only the pairs whose new price is 20 or less.
- Line 2 builds the new object from the pairs that are left, and line 7 prints it.
Move the sliders and watch each step change. The prices object itself never changes.
Where you will use this
You'll make this round trip whenever an object needs a small change before you show it, save it, or send it somewhere.
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);- Line 1 makes a
userwith the keysfirst_nameandlast_name. - Line 3 turns it into pairs.
([key, value])names the two parts of each pair. - Line 4 makes the new key.
key.replace("_", "")removes the first underscore. - Line 5 makes the new value.
value.toUpperCase()turns the text into capital letters. - Line 8 prints
{ firstname: "ADA", lastname: "LOVELACE" }.
Pick, omit, and swap
The next three functions all follow the same round trip. Each one uses keys.includes(key), which gives true when the array keys contains key.
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(lines 1–5) keeps only the keys you list. Use it to keep safe fields, like a name and an email.omit(lines 7–11) removes the keys you list. The!on line 9 means "not", so it keeps every key that is not in the list.invert(lines 13–17) swaps each key and value, so values become keys. This is useful for looking things up the other way. But if two keys share a value, the later one replaces the earlier one.
Prepare form data for display
const form = { name: "Asha", email: "asha@example.com", subscribed: true };
const labels = Object.fromEntries(
Object.entries(form).map(([key, value]) => [key, String(value)])
);
console.log(Object.keys(form));
console.log(labels);A form often stores text, numbers, and true or false. A simple list on a page needs only text.
- Line 1 makes a
formobject. Itssubscribedvalue istrue, not text. - Line 3 keeps each key and turns each value into text with
String(value). - Line 5 prints the field names:
["name", "email", "subscribed"]. - Line 6 prints the new object. Every value is now text, so
subscribedis"true".
Changing the shape of data does not keep it safe. In a real app, choose which fields are allowed before you show them on a page or send them to a server. The next example does that.
const profile = { name: "Asha", email: "asha@example.com", password: "secret" };
const publicProfile = Object.fromEntries(
Object.entries(profile).filter(([key]) => ["name", "email"].includes(key))
);
console.log(publicProfile);Line 3 keeps a pair only if its key is "name" or "email". So the password never gets into publicProfile. Line 5 prints { name: "Asha", email: "asha@example.com" }.
A list of allowed fields is safer than removing one field you know about. If someone adds a new secret field later, it stays out.
Count, check for empty, and add up 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);- Line 1 makes a
scoresobject with three scores. - Line 2 counts the keys and prints 3.
- Line 3 adds up the values and prints 26.
.reducewalks through the array and keeps a running total, starting from 0. Afor…ofloop over the values would work just as well. - Line 4 checks whether an empty object
{}has no keys, and printstrue.
So Object.keys(obj).length === 0 is the usual way to check that a plain object is empty.
Choosing the right tool
SORTEREach row is one tool. Read across to see which keys it looks at, what it gives back, and when to use it.
| Tool | Which keys does it look at? | What does it give back? | When do you use it? |
|---|---|---|---|
for…in | The object's own string keys, plus keys it borrows from its parent object. | One key at a time, inside a loop. | When you really do want the borrowed keys too. This is rare. |
Object.keys(obj) | Only the object's own string keys that may show in lists. | An array of the keys. | To count properties, check for an empty object, or show field names. |
Object.values(obj) | The same keys as Object.keys. | An array of the values. | To add up scores or check every status. |
Object.entries(obj) | The same keys as Object.keys. | An array of [key, value] pairs. | To change, keep, or rename properties and build a new object. |
To choose, ask one question: do you need the names, the values, or both together?
- Count how many settings an object has
- Add up all the numbers in a scores object
- Rename
first_nametofirstNameand keep its value - Show a list of a form's field names
- Find the average of every price
- Keep only items that cost under 20, and make a new object from them
Put each task under the method that gives the most useful array to start with.
Common misconceptions
"Object.keys is the same as for…in."
Not quite. for…in also visits keys borrowed from a parent object. Object.keys gives an array of the object's own keys only.
"These methods include symbol keys."
They skip symbol keys. The next lesson, Symbols, explains them. When you do need symbol keys, you can use Object.getOwnPropertySymbols or Reflect.ownKeys.
"Keys always come out in the order I added them."
Keys that look like whole numbers, like "2", come first, from smallest to largest. Other string keys come after, in the order you added them. The step-through shows this.
"Object.fromEntries keeps both values of a repeated key."
It can't. An object holds one value for each key. A later pair with the same key replaces the earlier one.
"The round trip changes the first object."
No. Object.entries, then .map or .filter, then Object.fromEntries builds a new object. The first object stays the same, unless your own code changes it on purpose.
Practice: object lists and round trips
5 EXERCISESThe first exercises ask what a short program prints. The later ones ask you to write a small function. Guess first, then use the hints if you get stuck.
What number does this program print?
const pet = { name: "Miso", kind: "cat", age: 4 };
console.log(Object.keys(pet).length);Object.keys(pet) is ["name", "kind", "age"]. That array has 3 items, so it prints 3.
Use Object.entries, .map, and Object.fromEntries to make a new object with every price doubled. What does it print?
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);Object.entries keeps each item name next to its price. map doubles each price. Object.fromEntries builds { apple: 4, bread: 6 }.
Write a pick function that keeps only the keys in the list. What should pick(user, ["id", "name"]) give back?
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 pairs keeps each key next to its value. Object.fromEntries turns the pairs that are left back into an object.
Does this program print true or false?
const cart = {};
console.log(Object.keys(cart).length === 0);Object.keys(cart) is []. [].length is 0, and 0 === 0 is true.
This code swaps the keys and values of a small object. Two keys share the value D. Which old key ends up as the value of D?
const codes = { draft: "D", published: "P", archived: "D" };
console.log(Object.fromEntries(
Object.entries(codes).map(([key, value]) => [value, key])
));The swapped pairs are ["D", "draft"], ["P", "published"], and ["D", "archived"]. The last D pair replaces the first one, so D holds archived.
Quiz: check your understanding
7 QUESTIONSFor each question, first ask: does it want the names, the values, or the pairs? Pick an answer, then read the explanation for every choice.
Question 1 of 7Which method gives 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 when a key repeats?
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 7In what order does Object.keys print keys that look like whole numbers?
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 steps make a changed copy of an object and leave the first object as it was?
Choose an answer to see the explanation.
Key takeaways
Object.keys(obj)gives an array of the object's own, enumerable, string keys.Object.values(obj)gives the values of those same keys, in the same order.Object.entries(obj)gives[key, value]pairs. Pairs are the easiest shape to change.Object.fromEntries(pairs)builds a new object. If a key repeats, the last value wins.- To change an object, make the round trip:
Object.entries, then.mapor.filter, thenObject.fromEntries.
Remember the one-liner.
Turn an object into an array when you need array tools. Turn the pairs back into an object when you are done.
Up next: Symbols, the special keys that these three methods skip.