Objects are the fundamental data structure of JavaScript โ every value that is not a primitive is an object. An object is a collection of key-value pairs called properties, where keys are strings (or Symbols) and values can be anything. Understanding objects deeply โ how to create, read, update, delete, and iterate their properties โ is the foundation of all JavaScript programming. In this lesson you will master object literals, property shorthand, computed keys, destructuring, and the essential Object.* utility methods.
Object Creation and Property Access
| Syntax | Example | Notes |
|---|---|---|
| Object literal | const obj = { key: value } |
Always prefer โ most readable |
| Property shorthand | const obj = { name, age } |
When variable name matches key |
| Computed key | const obj = { [expr]: value } |
Key evaluated at runtime |
| Dot notation | obj.name |
Use when key is a valid identifier |
| Bracket notation | obj['key'] or obj[variable] |
Dynamic keys or special characters |
| Optional chaining | obj?.nested?.prop |
Safe access โ returns undefined if null |
Object Destructuring Patterns
| Pattern | Syntax | Effect |
|---|---|---|
| Basic | const { name, age } = user |
Extract by key name |
| Rename | const { name: userName } = user |
Assign to different variable |
| Default value | const { role = 'viewer' } = user |
Fallback when key is undefined |
| Rename + default | const { role: r = 'viewer' } = user |
Both together |
| Rest properties | const { id, ...rest } = user |
id extracted; rest = remaining props |
| Nested | const { address: { city } } = user |
Unpack nested objects |
| In function params | function f({ name, age = 0 } = {}) |
Destructure argument inline |
Object.* Utility Methods
| Method | Returns | Use For |
|---|---|---|
Object.keys(obj) |
Array of own enumerable keys | Iterate keys |
Object.values(obj) |
Array of own enumerable values | Iterate values |
Object.entries(obj) |
Array of [key, value] pairs |
Iterate key-value pairs |
Object.fromEntries(arr) |
Object from [key, value] pairs |
Convert Map or entries back to object |
Object.freeze(obj) |
Frozen object | Prevent all modifications |
Object.hasOwn(obj, key) |
Boolean | Check own property (ES2022) |
obj[1] = 'one' โ JavaScript silently converts it to the string '1'. Object.keys() always returns an array of strings. If you need non-string keys, use a Map instead.Object.fromEntries() paired with Object.entries() is a powerful pattern for transforming objects: Object.fromEntries(Object.entries(obj).map(([k, v]) => [k, transform(v)])). This lets you apply array methods to object properties and convert the result back into an object.null or undefined throws a TypeError. Always guard against missing data: const { name } = user ?? {} or use a default parameter: function f({ name } = {}).Basic Example
// โโ Property shorthand and computed keys โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const name = 'Alice';
const age = 30;
const user = { name, age, role: 'admin' }; // { name: 'Alice', age: 30, role: 'admin' }
const field = 'email';
const config = {
[field]: 'alice@example.com',
[`${field}Verified`]: true,
};
console.log(config); // { email: 'alice@example.com', emailVerified: true }
// โโ Reading and writing โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const product = { id: 1, name: 'Widget', price: 9.99 };
console.log(product.name); // 'Widget'
console.log(product['price']); // 9.99
console.log(product?.meta?.sku); // undefined โ no crash
product.inStock = true; // add
product.price = 11.99; // update
delete product.id; // remove
// โโ Destructuring โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const { name: productName, price = 0, category = 'general' } = product;
console.log(productName, price, category); // 'Widget' 11.99 'general'
// โโ Rest properties โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const { id: userId, ...profile } = { id: 42, name: 'Bob', age: 25, email: 'b@b.com' };
console.log(userId); // 42
console.log(profile); // { name: 'Bob', age: 25, email: 'b@b.com' }
// โโ Nested destructuring โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const response = {
status: 200,
data: { user: { name: 'Carol', address: { city: 'London' } } }
};
const { data: { user: { name: cName, address: { city } } } } = response;
console.log(cName, city); // 'Carol' 'London'
// โโ Object.entries + for...of โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const scores = { alice: 95, bob: 82, carol: 88 };
for (const [student, score] of Object.entries(scores)) {
const grade = score >= 90 ? 'A' : score >= 80 ? 'B' : 'C';
console.log(`${student}: ${score} (${grade})`);
}
// โโ Transform via entries + fromEntries โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const prices = { widget: 9.99, gadget: 49.00, doohickey: 4.99 };
const withTax = Object.fromEntries(
Object.entries(prices).map(([k, v]) => [k, +(v * 1.08).toFixed(2)])
);
console.log(withTax); // { widget: 10.79, gadget: 52.92, doohickey: 5.39 }
// โโ Immutable spread merge โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
const defaults = { theme: 'light', lang: 'en', fontSize: 16 };
const saved = { theme: 'dark', fontSize: 18 };
const settings = { ...defaults, ...saved }; // saved values win
console.log(settings); // { theme: 'dark', lang: 'en', fontSize: 18 }
How It Works
Step 1 โ Objects Are Reference Types
Assigning an object to a variable stores a reference (memory address), not a copy. const b = a means both variables point to the same object โ modifying b.name changes a.name too. Use spread { ...a } for a shallow copy.
Step 2 โ Destructuring Matches by Key Name
Object destructuring assigns by key name, not position. { name: userName } reads the name key but stores it in a variable named userName. Defaults activate only when the value is undefined โ not for null, 0, or false.
Step 3 โ Spread Merges Shallowly โ Last Wins
{ ...defaults, ...saved } copies all properties into a new object. When the same key appears in both, the right-most value wins. This is the standard pattern for applying user settings over defaults.
Step 4 โ Object.entries Enables Array Pipelines on Objects
Object.entries(obj) converts an object to an array of [key, value] pairs. Process with any array method. Object.fromEntries() converts back. This round-trip lets you filter, map, and sort object properties cleanly.
Step 5 โ Computed Keys Enable Dynamic Objects
[expr]: value evaluates expr at runtime and uses its string value as the key. This powers patterns like building form state ({ [fieldName]: fieldValue }) and grouped lookup structures.
Real-World Example: Settings Manager
// settings-manager.js
const DEFAULTS = Object.freeze({
theme: 'light',
language: 'en',
fontSize: 16,
autoSave: true,
});
function createSettingsManager(saved = {}) {
let current = { ...DEFAULTS, ...saved };
return {
get(key) { return key ? current[key] : { ...current }; },
set(key, value) { current = { ...current, [key]: value }; },
reset(key) { current = key ? { ...current, [key]: DEFAULTS[key] } : { ...DEFAULTS }; },
export() { return JSON.stringify(current); },
diff() {
return Object.fromEntries(
Object.entries(current).filter(([k, v]) => v !== DEFAULTS[k])
);
},
};
}
const mgr = createSettingsManager({ theme: 'dark', fontSize: 18 });
console.log(mgr.get('theme')); // 'dark'
console.log(mgr.get('language')); // 'en'
console.log(mgr.diff()); // { theme: 'dark', fontSize: 18 }
mgr.set('language', 'fr');
console.log(mgr.diff()); // { theme: 'dark', fontSize: 18, language: 'fr' }
mgr.reset('theme');
console.log(mgr.get('theme')); // 'light'
Common Mistakes
Mistake 1 โ Destructuring null/undefined
โ Wrong:
const { name } = getUser(); // TypeError if getUser() returns null
โ Correct:
const { name } = getUser() ?? {};
Mistake 2 โ Mutating a shared object reference
โ Wrong:
const b = a; b.x = 99; // a.x is now 99!
โ Correct:
const b = { ...a }; b.x = 99; // a unchanged
Mistake 3 โ for…in including inherited properties
โ Wrong:
for (const key in obj) { } // may include prototype properties
โ Correct:
for (const [key, val] of Object.entries(obj)) { } // own props only
Quick Reference
| Task | Code |
|---|---|
| Create | const o = { name, age, role: 'admin' } |
| Computed key | { [expr]: value } |
| Destructure + rename | const { name: userName } = user |
| Destructure + default | const { role = 'viewer' } = user |
| Rest properties | const { id, ...rest } = obj |
| Shallow merge | { ...defaults, ...overrides } |
| Transform object | Object.fromEntries(Object.entries(o).map(...)) |
| Iterate entries | for (const [k,v] of Object.entries(obj)) |