Object Basics and Destructuring

โ–ถ Try It Yourself

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)
Note: Object keys are always strings (or Symbols) internally. When you use a number as a key โ€” 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.
Tip: 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.
Warning: Destructuring 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

▶ Try It Yourself

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))

🧠 Test Yourself

Given const user = { name: 'Alice', role: 'admin' }, what does const { role: r = 'viewer' } = user assign to r?





โ–ถ Try It Yourself