Objects — Keys, Spread and Immutable Updates
BeginnerObjects are the workhorse structure. Reading, iterating and — most importantly — updating them without mutation is the skill that carries straight into React state.
Overview
An object is an unordered set of key-value pairs where keys are strings or symbols. Numeric-looking keys are converted to strings, which explains a few oddities. What matters most in practice is updating: because objects are references, changing one in place can affect code you did not write, and in React it means a component will not re-render because the reference is unchanged. The spread pattern for immutable updates is worth making automatic.
Access, Iteration, and Dynamic Keys
Dot notation for known keys, brackets for computed ones. Object.entries is usually what you want for iteration.
const user = { name: 'Asha', role: 'student' }
user.name // known key
user['role'] // same thing
const key = 'role'
user[key] // computed key
Object.keys(user) // ['name', 'role']
Object.values(user) // ['Asha', 'student']
Object.entries(user) // [['name','Asha'], ['role','student']]
for (const [k, v] of Object.entries(user)) { ... }
// Building an object from pairs, and back:
Object.fromEntries([['a', 1], ['b', 2]]) // { a: 1, b: 2 }
// Computed keys in a literal:
const field = 'email'
const patch = { [field]: 'a@b.com', [`${field}Verified`]: false }Immutable Updates
The pattern you will use in every reducer and every setState. Spread copies one level; nested updates need spreading at each level.
const state = {
user: { name: 'Asha', address: { city: 'Pune' } },
items: [1, 2],
}
// Top-level field
const next = { ...state, loading: false }
// Nested — spread each level you are changing
const moved = {
...state,
user: {
...state.user,
address: { ...state.user.address, city: 'Mumbai' },
},
}
// Arrays inside objects
const added = { ...state, items: [...state.items, 3] }
const removed = { ...state, items: state.items.filter(i => i !== 1) }
// Removing a key
const { user, ...withoutUser } = stateOptional Chaining and Safe Reads
API responses are the main source of deeply nested optional data, and these operators exist for exactly that.
// Reading what might not be there
const city = response?.data?.user?.address?.city ?? 'Unknown'
// Checking existence properly
'name' in user // true, includes inherited
Object.hasOwn(user, 'name') // true, own properties only
user.name !== undefined // fails if the key exists with value undefined
// Merging, later wins
const config = { ...defaults, ...userConfig }
// Shallow equality — why React re-renders
const a = { x: 1 }
const b = { x: 1 }
a === b // false — different referencesKey Points to Remember
- 1Object.entries() with destructuring is the idiomatic way to iterate key-value pairs
- 2Spread copies one level deep — nested updates require spreading at every level you change
- 3Removing a key is done with rest destructuring: const { drop, ...rest } = obj
- 4Object.hasOwn() checks own properties; the `in` operator also finds inherited ones
- 5Two objects with identical contents are not ===; this reference comparison is why React re-renders on new objects
Interview Questions
Sign in to ask AriaHow do you copy an object in JavaScript? What does "shallow" mean here?
How would you update a deeply nested field without mutating the original object?
Why does { a: 1 } === { a: 1 } evaluate to false?
Ask Aria about Objects — Keys, Spread and Immutable Updates
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.