Working with Objects (Advanced)

You already know how to create objects, read their properties, and write methods. Now let's learn the power tools 🧰 that professional developers use every day with objects.

Here's what's in this lesson:

#TopicIn one line
1Computed propertiesCreate keys from variables
2Object destructuringUnpack properties into variables
3Optional chainingRead deep values safely
4Getters and settersProperties that run code
5Object copyingMake a copy instead of sharing
6Shallow vs deep copyHow deep the copy goes
7Object.keys/values/entriesTurn objects into arrays
8Property descriptorsHidden settings of every property
9SymbolsTruly unique keys

1. Computed Properties

Normally, you write a key directly:

const user = { name: "Priya" };

But what if the key name is stored in a variable, or needs to be built at runtime? Use square brackets [ ] around the key. This is called a computed property.

Think of it like a name slip 🏷️: instead of writing the label directly on the box, you write "use whatever name is on this slip."

Building keys with expressions

Real example: updating a form field 📝

One function that can update any field, based on which input changed:


2. Object Destructuring

Destructuring means unpacking properties from an object into separate variables, in one line.

Think of opening a tiffin box 🍱 and putting the roti, dal, and sabzi on separate plates.

Without destructuring

const student = { name: "Aarav", age: 20, city: "Delhi" };

const name = student.name;
const age = student.age;
const city = student.city;

With destructuring ✨

Key difference from arrays: Array destructuring works by position. Object destructuring works by key name, so the order doesn't matter!

Renaming variables

Use key: newName to give the variable a different name.

Default values

If a property is missing, use a default value with =.

Collecting the rest with ...

Destructuring nested objects

Destructuring in function parameters ⭐

This is very common in real projects. You can unpack an object right in the function's brackets.


3. Optional Chaining ?.

When you read a value deep inside an object, a missing part in the middle causes an error. 💥

Optional chaining ?. says: "Go further only if this part exists. Otherwise, stop and give undefined."

It's like asking a security guard 💂 at each gate: "Is this gate open?" If not, you simply turn back, instead of crashing into it.

With a default value ??

With arrays and methods

SyntaxUse for
obj?.keyA property
obj?.[key]A property with brackets, or an array item
obj.method?.()A method that might not exist

⚠️ Don't use ?. everywhere. Use it only where a value might really be missing, such as data coming from a server.


4. Getters and Setters

Sometimes you want a property that runs some code when you read it or change it. That's what getters and setters do.

KeywordRuns when you...
GettergetRead the property
SettersetChange the property

Getters: calculated properties

Notice: you read student.fullName like a normal property, not like a method fullName().

Setters: checking values before saving ✅

A setter works like a security check 🛂: it inspects the value before letting it in.

Real example: temperature converter 🌡️


5. Object Copying

Objects are shared, not copied, when you assign them to another variable.

It's like sharing a Google Doc link: if your friend edits it, you see the change too, because there is only one document.

To get your own separate copy, use one of these:

Spread operator ... (most common ✅)

Object.assign()

Copying and changing at the same time


6. Shallow vs Deep Copying

This is where many developers get confused, so let's go slowly. 🐢

Shallow copy: only the top level is copied

Shallow copying** creates a new object, but nested objects or arrays are still shared with the original object.

{ ...obj } and Object.assign() make a shallow copy. The top-level properties are copied, but objects inside are still shared.

Think of photocopying a file folder 📁. The first page is copied, but it has a note saying "see the attached Aadhaar card." Both folders point to the same Aadhaar card!

Deep copy: everything is copied

Deep copying creates a completely independent copy, including all nested objects and arrays.

A deep copy copies every level, so nothing is shared. Use structuredClone().

The old trick: JSON.parse(JSON.stringify())

You may see this in older code. It works for simple data, but it loses functions, undefined, and dates.

Quick comparison

MethodTypeNested objects
b = a❌ Not a copyEverything is shared
{ ...a }Shallow copyNested objects are shared
Object.assign({}, a)Shallow copyNested objects are shared
structuredClone(a)✅ Deep copyFully separate (functions not allowed)
JSON.parse(JSON.stringify(a))Deep copy (old)Loses functions, dates, undefined

Simple rule: If your object has no nested objects, use { ...obj }. If it does, use structuredClone(obj).


7. Object.keys, Object.values, and Object.entries

These three methods turn an object into an array, so you can use array tools like map, filter, reduce, and for...of.

MethodReturnsExample result
Object.keys(obj)An array of keys["Maths", "Science"]
Object.values(obj)An array of values[92, 88]
Object.entries(obj)An array of key, value pairs[["Maths", 92], ...]

Real examples

Going back: Object.fromEntries()

Object.fromEntries() turns key, value pairs back into an object. Combine it with entries() to transform objects.


8. Property Descriptors

Every property has some hidden settings 🔧 behind it, like the settings of an app on your phone. These settings are called property descriptors.

SettingMeaningIf false
valueThe actual data—
writableCan the value be changed?It becomes read-only
enumerableDoes it show up in loops and Object.keys()?It stays hidden
configurableCan the property be deleted or its settings changed?It is locked

For normal properties, all three are true.

Creating a read-only property

Use Object.defineProperty() to set these options yourself.

Hiding a property from loops

⚠️ defineProperty() sets everything to false by default, unless you say otherwise.

Locking a whole object

MethodAdd new?Delete?Change values?
Object.preventExtensions(obj)❌✅✅
Object.seal(obj)❌❌✅
Object.freeze(obj)❌❌❌

9. Symbols

A Symbol is a special value that is always unique. No two symbols are ever the same, even if they have the same description.

Think of two people both named "Rahul Sharma" 👥. Same name, but each has a different Aadhaar number. A symbol is like that Aadhaar number: completely unique.

Using a symbol as an object key

Symbols are used as keys that can never clash with other keys.

Symbol keys are hidden from normal loops

Why are symbols useful?

Imagine you're using an object from someone else's code (a library), and you want to add your own property. If you use a normal key like id, you might overwrite their id by mistake! 😱

A symbol key never clashes:

As a beginner, you won't use symbols often. Just remember: symbols are unique, hidden keys. JavaScript also uses built-in symbols internally, like Symbol.iterator, which makes for...of work.


Common Mistakes to Avoid

MistakeProblemFix
{ field: "Pune" } when the key is in a variableCreates a key literally named "field"Use { [field]: "Pune" }
Destructuring a key that doesn't existGets undefinedGive a default: { city = "Delhi" }
Reading deep values without checking❌ TypeErrorUse ?.
Writing obj.fullName() for a getter❌ TypeError: not a functionWrite obj.fullName
Copying with b = aBoth share the same objectUse { ...a } or structuredClone(a)
Using { ...a } for nested objectsNested parts are still sharedUse structuredClone(a)
Expecting symbol keys in Object.keys()Symbols are hiddenUse Object.getOwnPropertySymbols()

Quick Summary Table

TopicExample
Computed property{ [key]: value }
Destructuringconst { name, age } = user;
Rename + defaultconst { name: userName, city = "Delhi" } = user;
Optional chaininguser.address?.city ?? "N/A"
Getterget fullName() { return ... }
Setterset age(v) { if (v > 0) this._age = v; }
Shallow copy{ ...obj }
Deep copystructuredClone(obj)
Keys / values / pairsObject.keys(), Object.values(), Object.entries()
Pairs back to objectObject.fromEntries(pairs)
Read-only propertyObject.defineProperty(obj, "x", { value: 1, writable: false })
Unique keyconst id = Symbol("id"); obj[id] = 1;

Key Takeaways

  • Computed properties { [key]: value } let you create keys from variables, and destructuring const { a, b } = obj unpacks properties by name.
  • Optional chaining ?. safely reads nested values that might be missing. Combine it with ?? for a default.
  • Getters run code when a property is read, and setters run code when it is changed, which is great for calculated values and validation.
  • { ...obj } makes a shallow copy (nested objects are still shared). Use structuredClone() for a deep copy.
  • Property descriptors control whether a property can be changed, looped over, or deleted, and symbols create unique, hidden keys that never clash.