JavaScript Object Methods: keys, values, entries, assign, freeze
Use Object.keys, values, entries, assign, freeze and seal to loop over, copy, merge and protect objects in JavaScript, with simple real-life examples.
What you will learn
In the last lesson you learned how to create objects and read their properties. But real programs need more: How many properties does this object have? Can I loop over it? How do I copy it or merge two objects? How do I stop other code from changing it? JavaScript has a built-in toolbox called Object for exactly this. In this lesson you will learn Object.keys, Object.values, Object.entries, Object.assign, Object.freeze and Object.seal, plus Object.fromEntries, which is a very useful partner for entries.
A note about how they are called
These are not called on your object like student.keys(). You call them on the big Object and pass your object in:
const student = { name: "Riya", age: 20 };
console.log(Object.keys(student)); // ["name", "age"]
// student.keys(); // TypeError: student.keys is not a function
Object.keys(): get all the keys
It returns an array of the property names (as strings).
const cart = { pen: 10, notebook: 60, bag: 450 };
const names = Object.keys(cart);
console.log(names); // ["pen", "notebook", "bag"]
console.log(names.length); // 3
Because the result is a normal array, you can use every array method on it:
Object.keys(cart).forEach((name) => {
console.log(name);
});
// pen
// notebook
// bag
Count the properties
An object has no .length, but Object.keys gives you a way:
const user = { name: "Riya", age: 20, city: "Delhi" };
console.log(Object.keys(user).length); // 3
Check if an object is empty
function isEmpty(obj) {
return Object.keys(obj).length === 0;
}
console.log(isEmpty({})); // true
console.log(isEmpty({ a: 1 })); // false
Object.values(): get all the values
It returns an array of the values.
const cart = { pen: 10, notebook: 60, bag: 450 };
const prices = Object.values(cart);
console.log(prices); // [10, 60, 450]
Now maths becomes easy:
const total = Object.values(cart).reduce((sum, price) => sum + price, 0);
console.log(total); // 520
const highest = Math.max(...Object.values(cart));
console.log(highest); // 450
Object.entries(): get key and value together
It returns an array of [key, value] pairs. Each pair is a small array of two items.
const cart = { pen: 10, notebook: 60, bag: 450 };
console.log(Object.entries(cart));
// [["pen", 10], ["notebook", 60], ["bag", 450]]
The best way to use it is with for...of and destructuring (unpacking each pair into two variables, which you will study in detail in a later lesson):
for (const [name, price] of Object.entries(cart)) {
console.log(`${name} costs ₹${price}`);
}
// pen costs ₹10
// notebook costs ₹60
// bag costs ₹450
Quick comparison
| Method | Gives you | For { a: 1, b: 2 } |
|---|---|---|
Object.keys(obj) |
Array of keys | ["a", "b"] |
Object.values(obj) |
Array of values | [1, 2] |
Object.entries(obj) |
Array of [key, value] pairs |
[["a", 1], ["b", 2]] |
All three return only the object’s own, enumerable properties. Inherited ones are left out, which is why many developers prefer them to for...in.
Object.fromEntries(): the reverse of entries
Object.fromEntries turns an array of [key, value] pairs back into an object. Together with entries, it lets you transform an object using array methods:
const prices = { pen: 10, notebook: 60, bag: 450 };
// Give 10% discount on every item
const discounted = Object.fromEntries(
Object.entries(prices).map(([name, price]) => [name, price * 0.9])
);
console.log(discounted); // { pen: 9, notebook: 54, bag: 405 }
The pattern is always: entries, then array methods, then fromEntries.
Filtering an object works the same way:
const expensive = Object.fromEntries(
Object.entries(prices).filter(([name, price]) => price > 50)
);
console.log(expensive); // { notebook: 60, bag: 450 }
Object.assign(): copy and merge
Object.assign(target, ...sources) copies the properties of the sources into the target and returns the target.
const target = { a: 1 };
const source = { b: 2, c: 3 };
Object.assign(target, source);
console.log(target); // { a: 1, b: 2, c: 3 }
Notice that the target itself was changed. That is often not what you want, so the usual trick is to use a new empty object as the target.
Make a copy
const original = { name: "Riya", age: 20 };
const copy = Object.assign({}, original);
copy.name = "Karan";
console.log(original.name); // "Riya" (unchanged)
console.log(copy.name); // "Karan"
Merge objects: later ones win
If two sources have the same key, the last one wins.
const defaults = { theme: "light", fontSize: 16, language: "en" };
const userChoice = { theme: "dark", fontSize: 18 };
const settings = Object.assign({}, defaults, userChoice);
console.log(settings);
// { theme: "dark", fontSize: 18, language: "en" }
The user’s choices override the defaults, and anything the user did not choose keeps its default value.
It is a shallow copy
Object.assign copies only the first level. Nested objects are shared, not copied:
const original = {
name: "Riya",
address: { city: "Delhi" }
};
const copy = Object.assign({}, original);
copy.address.city = "Mumbai";
console.log(original.address.city); // "Mumbai" (changed too!)
copy.address and original.address point to the same inner object. For a fully independent copy, modern JavaScript has structuredClone:
const deepCopy = structuredClone(original);
deepCopy.address.city = "Pune";
console.log(original.address.city); // "Mumbai" (safe this time)
Tip: the spread syntax
{ ...a, ...b }does the same job asObject.assign({}, a, b)and is more popular today. You will learn it in the destructuring, spread and rest lesson.Object.assignis still important to know, because you will see it in a lot of existing code.
Object.freeze(): lock an object completely
Object.freeze(obj) makes the object read-only. You cannot add, change or delete anything.
const config = Object.freeze({
appName: "MyCodeNest",
version: 1
});
config.version = 2; // ignored
config.author = "Riya"; // ignored
delete config.appName; // ignored
console.log(config); // { appName: "MyCodeNest", version: 1 }
It fails silently (unless you use strict mode)
In normal code, the forbidden change is silently ignored. No error, no change. In strict mode it throws a TypeError:
function tryToChange() {
"use strict";
const frozen = Object.freeze({ level: 1 });
frozen.level = 2;
}
try {
tryToChange();
} catch (error) {
console.log(error.name); // "TypeError"
}
(Strict mode has its own lesson later. Modules and classes use it automatically.)
Check if it is frozen
const a = Object.freeze({ x: 1 });
const b = { x: 1 };
console.log(Object.isFrozen(a)); // true
console.log(Object.isFrozen(b)); // false
Freeze is shallow too
Only the first level is locked. Inner objects and arrays can still change:
const settings = Object.freeze({
theme: "dark",
colors: ["red", "blue"]
});
settings.theme = "light"; // ignored
settings.colors.push("green"); // works! the inner array is not frozen
console.log(settings.theme); // "dark"
console.log(settings.colors); // ["red", "blue", "green"]
To freeze deeply, freeze the inner parts as well:
const settings2 = Object.freeze({
theme: "dark",
colors: Object.freeze(["red", "blue"])
});
console.log(Object.isFrozen(settings2.colors)); // true
Object.seal(): lock the structure, not the values
Object.seal(obj) is a little softer than freeze:
- You can change the values of existing properties.
- You cannot add new properties.
- You cannot delete properties.
const user = Object.seal({ name: "Riya", age: 20 });
user.age = 21; // allowed: changing a value
user.city = "Delhi"; // ignored: cannot add
delete user.name; // ignored: cannot delete
console.log(user); // { name: "Riya", age: 21 }
console.log(Object.isSealed(user)); // true
freeze vs seal vs a normal object
| Action | Normal object | Object.seal |
Object.freeze |
|---|---|---|---|
| Read properties | Yes | Yes | Yes |
| Change a value | Yes | Yes | No |
| Add a property | Yes | No | No |
| Delete a property | Yes | No | No |
| Check function | n/a | Object.isSealed |
Object.isFrozen |
A frozen object is also sealed. Neither one can be undone: there is no “unfreeze”.
Real-life use cases
1. Show a cart as a table
const cart = { pen: 10, notebook: 60, bag: 450 };
for (const [item, price] of Object.entries(cart)) {
console.log(item.padEnd(10) + "₹" + price);
}
// pen ₹10
// notebook ₹60
// bag ₹450
2. Calculate a total and an average
const marks = { maths: 82, science: 91, english: 76 };
const values = Object.values(marks);
const total = values.reduce((sum, m) => sum + m, 0);
const average = total / values.length;
console.log(total); // 249
console.log(average.toFixed(1)); // "83.0"
3. Find the best subject
const marks = { maths: 82, science: 91, english: 76 };
const [bestSubject, bestMarks] = Object.entries(marks).sort((a, b) => b[1] - a[1])[0];
console.log(bestSubject, bestMarks); // "science" 91
4. Build a URL query string
const filters = { category: "shoes", size: 9, sort: "price" };
const query = Object.entries(filters)
.map(([key, value]) => `${key}=${value}`)
.join("&");
console.log("/products?" + query); // "/products?category=shoes&size=9&sort=price"
(Later you will meet URLSearchParams, which does this for you.)
5. Default settings plus user options
function createChart(userOptions) {
const defaults = { width: 400, height: 300, color: "blue" };
return Object.assign({}, defaults, userOptions);
}
console.log(createChart({ color: "green" }));
// { width: 400, height: 300, color: "green" }
6. Constants that nobody can change
const ROLES = Object.freeze({
ADMIN: "admin",
EDITOR: "editor",
VIEWER: "viewer"
});
ROLES.ADMIN = "hacker"; // ignored
console.log(ROLES.ADMIN); // "admin"
7. Remove empty fields before sending data
const form = { name: "Riya", phone: "", city: "Delhi", email: "" };
const cleaned = Object.fromEntries(
Object.entries(form).filter(([key, value]) => value !== "")
);
console.log(cleaned); // { name: "Riya", city: "Delhi" }
8. Count how many times each item appears
const votes = ["js", "css", "js", "html", "js", "css"];
const count = {};
for (const vote of votes) {
count[vote] = (count[vote] || 0) + 1;
}
console.log(count); // { js: 3, css: 2, html: 1 }
const winner = Object.entries(count).sort((a, b) => b[1] - a[1])[0][0];
console.log(winner); // "js"
9. Fixed form fields with seal
const form = Object.seal({ name: "", email: "" });
form.name = "Riya"; // fine: filling a field
form.phone = "9999999999"; // ignored: no new fields allowed
console.log(form); // { name: "Riya", email: "" }
Common mistakes
- Writing
obj.keys(). It must beObject.keys(obj). - Forgetting that
Object.assignchanges the first argument. UseObject.assign({}, a, b)to leaveauntouched. - Thinking
assignmakes a deep copy. Nested objects are still shared. UsestructuredClonefor a deep copy. - Expecting
freezeto work deeply. Inner objects and arrays can still change. - Expecting an error from
freeze. In normal mode the change is silently ignored. Use strict mode if you want an error. - Trying to “unfreeze” an object. It is permanent. Make a new copy instead.
- Confusing
sealandfreeze.sealstill lets you change existing values. - Using
Object.keysonnullorundefined. It throws aTypeError. - Forgetting that keys come back as strings, even if you wrote them as numbers.
- Using
for...ofdirectly on an object. It fails. Loop overObject.entries(obj)instead.
Practice
- Create
const car = { brand: "Tata", model: "Nexon", year: 2024 };and print its keys, its values and its entries. - Print how many properties
carhas. - Write
isEmpty(obj)and test it with{}and{ a: 1 }. - Create
const prices = { tea: 15, coffee: 25, juice: 40 };. UseObject.valuesandreduceto find the total. Then find the most expensive price withMath.max. - Loop over
priceswithfor...ofandObject.entries, and printtea costs ₹15and so on. - Use
Object.fromEntriesandmapto make a new object where every price is doubled. - Use
Object.fromEntriesandfilterto keep only items that cost less than 30. - Merge
{ a: 1, b: 2 }and{ b: 3, c: 4 }withObject.assignwithout changing either original. What is the value ofb? - Make an object with a nested
address. Copy it withObject.assign, change the copy’s city, and check the original. Then repeat withstructuredClone. What is different? - Challenge: freeze an object that contains an array. Show that you can still push into the array, then write a small
deepFreeze(obj)function that freezes every nested object too.
Recap
- Call these on
Object, passing your object:Object.keys(obj),Object.values(obj),Object.entries(obj). keysgives the property names,valuesgives the values, andentriesgives[key, value]pairs. All three return normal arrays, somap,filterandreducework on them.Object.fromEntriesconverts pairs back into an object. The pattern entries, array method, fromEntries transforms or filters objects.Object.assign(target, ...sources)copies and merges properties into the target. Use{}as the target to avoid changing your originals. Later sources win. It is a shallow copy.Object.freezeblocks adding, changing and deleting.Object.sealblocks adding and deleting, but allows changing existing values. Both are shallow and permanent.- Blocked changes are silently ignored in normal mode, and throw a
TypeErrorin strict mode. - Next you will learn the
thiskeyword: how JavaScript decides whatthismeans in the global scope, in objects, in regular functions and in arrow functions.