Skip to content
React Course1.0.0 beta
CSEN
React Course1.0.0 beta
CSEN
🏠 Home🧭 Where to start?🔁 Review📄 Cheat sheets📰 What's newℹ️ About the course
JavaScript0/22

JavaScript in general

  • 01 Variables, types and operators0/2
  • 02 Functions and closures0/2
  • 03 Objects0/2
  • 04 Arrays I: map, filter and friends0/2
  • 05 Arrays II: reduce, sorting and grouping0/3
  • 06 Conditions and logical operators0/2
  • 07 Asynchronous JavaScript0/2
  • 08 Modules and built-in tools0/2

JavaScript for React

  • 09 References and immutability0/3
  • 10 JS patterns you meet everywhere in React0/2
TypeScript0/6

Basics

  • 01 A quick review of the basics0/3
  • 02 State and events (useState)0/3

Hooks in depth

  • 03 Effects (useEffect)0/3
  • 04 Refs (useRef)0/3
  • 05 More complex state (useReducer)0/3
  • 06 Context0/3
  • 07 Custom hooks0/3

Forms

  • 08 Forms and React 19 Actions0/3

Performance

  • 09 Performance and rendering0/3

Patterns

  • 10 Component design patterns0/3

Ecosystem

  • 11 TypeScript with React0/3
  • 12 Routing (React Router)0/3
  • 13 Data fetching0/3
  • 14 Application state management0/3

Project

  • 15 Final project: Kanban0/2

Summary

  • 16 Summary: the principles of React

Your account

Privacy

JavaScript 03 · JavaScript in general

Objects

Dot vs. square brackets, destructuring, spread, Object.entries and dynamic keys.

Loading lesson…

💬 Found a mistake, something unclear, or have an idea? Let me know.
← Functions and closuresArrays I: map, filter and friends →

Before we start: an object is an index card

Picture the card catalogue in a library. Every card describes one book and has labelled fields: title, author, year. An object in JavaScript is exactly such a card – a set of named fields (properties), each with a value.

const book = {
title: 'The Little Prince', // key: value
author: 'Saint-Exupéry',
year: 1943,
available: true,
}

Objects are everywhere: a user, a product in the cart, the app's settings, a response from the server. In React, the props a component receives are an object too. If you can handle objects well, you write shorter and more readable code.

ℹ️ What's in this lesson
  1. Reading properties: dot vs. square brackets.
  2. Adding, changing and deleting a property.
  3. Shorthand syntax and computed keys.
  4. Destructuring in depth.
  5. Spread: copying and merging objects.
  6. Going through an object: keys, values, entries.
  7. An object as a dictionary.

1. Reading properties

You can read a field of the card in two ways: with a dot, or with square brackets holding the field's name as text in quotes.

const user = { name: 'Anna', city: 'London', 'favorite color': 'blue' }
user.name // 'Anna' – you write the property name after the dot
user['name'] // 'Anna' – the same, only the name is text in brackets
user['favorite color'] // 'blue' – a name with a space can only go in brackets
user.favorite color // ❌ error – a name after the dot can't contain a space

The property name in a variable

Square brackets can do something the dot can't: they don't need a fixed text inside. They can hold a variable – or any expression. JavaScript evaluates it first and only then uses the resulting text as the property name.

Imagine that at the library you get a slip of paper saying “year” and you are to read the field written on the slip. You don't look for a field called “slip” – you look at what the slip says and read the field year. A variable in square brackets is such a slip:

const field = 'city' // the variable field holds the TEXT 'city'
user[field] // 'London' – JavaScript fills in the value: user['city']
const whatever = 'name' // the variable can have any name
user[whatever] // 'Anna' – user['name']
user['ci' + 'ty'] // 'London' – the expression is worked out to 'city' first

Watch out for quotes – just add them and a completely different property is looked up:

SyntaxWhat JavaScript doesResult
✅ user[field]takes the value of the variable field ('city') and reads user.city'London'
❌ user['field']looks for a property literally called “field” – user has no such propertyundefined
❌ user.fieldthe same as user['field']undefined

What is it good for? For example, when you write a function that should be able to read any property – which one is decided only by whoever calls it:

const read = (obj, field) => obj[field]
read(user, 'name') // 'Anna'
read(user, 'city') // 'London'
// with obj.field both calls would return undefined – it would look for a property "field"
❓ Does the variable have to be called key?

No. In examples on the internet (and later in this lesson) you will often see it named key or field, but that's just a habit – key isn't a special word. user[key], user[whatever] and user[x] all work the same, as long as the variable holds a property name.

So when do you use which syntax?

SyntaxWhen
obj.nameYou know in advance which property you want – that is most cases.
obj[key]Which property to read is stored in a variable – say in a function parameter or while looping over an object.

Missing and nested properties

const order = {
id: 7,
customer: { name: 'Peter', address: { city: 'Boston' } },
}
order.customer.address.city // 'Boston' – read nested objects dot after dot
order.note // undefined – a property that doesn't exist isn't an error
order.delivery.date // 💥 TypeError – delivery is missing (it's undefined) and you can't read .date from undefined
order.delivery?.date // undefined – ?. sees that delivery is missing and doesn't read .date at all (more in lesson JavaScript 06)

2. Adding, changing, deleting

const user = { name: 'Anna' }
user.age = 31 // adds a new property
user.name = 'Anna S.' // changes an existing one
user['city'] = 'London' // the same with brackets
delete user.age // deletes a property
user // { name: 'Anna S.', city: 'London' }
⚠️ Change it, or copy it?
All of this changes the original object. In plain JS that's fine, but data held by React (state, props) must not be changed like this – instead you make an updated copy (spread below). Lesson JavaScript 09 explains why.

3. Shorthand syntax and computed keys

Three ways of writing that save you work when creating objects and that you will see in code all the time: a property from a variable of the same name, methods and computed keys.

A property from a variable of the same name

When a variable has the same name as the property you want to create, you don't have to write the name twice:

const name = 'Anna'
const age = 31
const user = { name: name, age: age } // long: the property name gets the value of the variable name
const user = { name, age } // short: the same
// both create { name: 'Anna', age: 31 }

Methods

A property of an object can hold a function too – then it's called a method. The object counter below has two properties: the number count and the method increment, which increases that number. A method has a shorter form too:

// long: a property increment whose value is a function
const counter = {
count: 0,
increment: function () {
this.count++ // this = the object you call the method on (here counter)
},
}
// short: the same, just without ": function"
const counter = {
count: 0,
increment() {
this.count++
},
}
counter.increment() // you call the method through the object and a dot
counter.count // 1

Computed key [ ]

When you don't know the property name in advance because it's stored in a variable, put it in square brackets when creating the object:

const field = 'email'
const value = 'anna@example.com'
const update = { [field]: value } // { email: 'anna@example.com' }
const wrong = { field: value } // { field: 'anna@example.com' } – literally "field"
// Typical use: one function for all the fields of a form
function updateForm(form, field, value) {
return { ...form, [field]: value }
}
updateForm({ name: '', email: '' }, 'name', 'Anna') // { name: 'Anna', email: '' }
const prefix = 'color'
const theme = { [`${prefix}Primary`]: 'blue' } // { colorPrimary: 'blue' }

4. Destructuring

Destructuring is unpacking a box: instead of "take the box and from it the thing labelled name" you say straight away "I want the things name and city".

const user = { name: 'Anna', city: 'London', age: 31 }
const { name, city } = user // two variables at once
const { name: userName } = user // renaming: the variable will be called userName
const { role = 'guest' } = user // a default value when the property is missing (or undefined)
const { name: n, role: r = 'guest' } = user // renaming and a default value
const { age, ...rest } = user // ... collects the remaining properties: rest = { name: 'Anna', city: 'London' }
// (rest is an ordinary variable name, it could be ...others too)

Nested destructuring

const order = { id: 7, customer: { name: 'Peter', address: { city: 'Boston' } } }
const { customer: { name, address: { city } } } = order
name // 'Peter'
city // 'Boston'
// customer and address weren't created as variables – we just "passed through" them
✨ Don't overdo it
Nested destructuring three levels deep is more of a riddle. const city = order.customer.address.city is often easier to read.

Destructuring in parameters

// The function gets an object and unpacks what it needs right away
function formatUser({ name, city = 'unknown' }) {
return `${name} (${city})`
}
formatUser({ name: 'Anna', city: 'London', age: 31 }) // 'Anna (London)'
// This is exactly what a React component looks like:
function UserCard({ name, city }) { … }
// It works in a callback too. map calls a function for every item of an array (more in lesson JavaScript 04)
// and here every item is a user object – the parameter unpacks name from it right away:
const users = [{ name: 'Anna', city: 'London' }, { name: 'Peter', city: 'Leeds' }]
users.map((user) => user.name) // without destructuring: ['Anna', 'Peter']
users.map(({ name }) => name) // with destructuring: the same

Destructuring arrays

An array isn't unpacked by name, but by position: the first variable gets the first item, the second one the second item and so on. That's why you choose the variable names yourself.

const [first, second] = ['apple', 'pear', 'plum']
// first = 'apple', second = 'pear' (plum is left over and isn't stored anywhere)
const [, , third] = ['apple', 'pear', 'plum']
// commas without a name skip the first two items: third = 'plum'
const [head, ...tail] = [1, 2, 3, 4]
// head = 1, tail = [2, 3, 4] – ... collects the rest, just like with an object

Why you need it: in React you will write this line in almost every component. The function useState returns an array of two items – the current value and a function that changes it – and destructuring names them right away:

const [count, setCount] = useState(0)
// useState(0) returns the array [0, function]
// count = 0 (the first item), setCount = the function that changes it (the second item)
const [name, setName] = useState('Anna') // you choose the names, the position decides

What exactly useState does you'll learn in the lesson on state. For now it's enough to recognise it as ordinary array destructuring.

5. Spread: copying and merging

Three dots before an object mean "pour all its properties in here".

const user = { name: 'Anna', city: 'London' }
const copy = { ...user } // a shallow copy: a new object, the same properties
copy === user // false – they are two different objects
const moved = { ...user, city: 'Boston' } // a copy with an overwritten property
const withAge = { ...user, age: 31 } // a copy with a new property
const defaults = { theme: 'light', lang: 'en', fontSize: 16 }
const saved = { theme: 'dark' }
const settings = { ...defaults, ...saved } // { theme: 'dark', lang: 'en', fontSize: 16 }
⚠️ Order matters – the last one wins
{ ...user, city: 'Boston' } // { name: 'Anna', city: 'Boston' } ✅ overwrites
{ city: 'Boston', ...user } // { city: 'London', name: 'Anna' } ❌ the spread overwrote it back

Conditional properties

Sometimes an object should get a property only under a certain condition – say the role property only for an administrator. You build it from two things: spread, which you already know, and an “either, or” choice.

The syntax condition ? A : B means “if the condition holds, take A, otherwise B” (lesson JavaScript 06 covers it in detail). Here it chooses between an object with the role property and an empty object – and spread then pours whatever came out into the new object:

const isAdmin = true
const user = {
name: 'Anna',
...(isAdmin ? { role: 'admin' } : {}),
}
// step by step, when isAdmin is true:
// 1. the parentheses choose { role: 'admin' }
// 2. ... pours it into the object → { name: 'Anna', role: 'admin' }
// and when isAdmin is false:
// 1. the parentheses choose {} – an empty object
// 2. ... has nothing to pour → { name: 'Anna' } – the role property isn't created at all

Why not simply role: isAdmin ? 'admin' : undefined? Then the role property would always be created, just with the value undefined for other users. With spread, other users don't have it at all.

❓ What does a “shallow” copy mean?

Spread copies only the first level of an object. When a property holds another object (here the address), it doesn't copy it – it puts only a reference to the same object into the copy. It's like photocopying an index card that says “address: see card no. 5”: you have two cards, but there is still just one card no. 5.

const user = { name: 'Anna', address: { city: 'London' } }
const copy = { ...user }
// copy has its own name, but copy.address and user.address are THE SAME object
copy.name = 'Eve'
// ✅ changes only copy – user.name is still 'Anna'
copy.address.city = 'Boston'
// 😱 changes the shared address object – user.address.city is now 'Boston' too

The fix: copy the nested object with spread too.

const moved = { ...user, address: { ...user.address, city: 'Boston' } }
// moved.address is a NEW object – user.address stayed { city: 'London' } ✅

Lesson JavaScript 09 on references goes into this in detail.

6. Going through an object

For going through an object JavaScript has three ready-made functions: Object.keys, Object.values and Object.entries. Unlike rest or field, which you named yourself, these names are fixed – you have to write them exactly like this, including the capital O in Object. Each of them returns an array (arrays are covered in detail in the next lesson):

FunctionReturns
Object.keys(obj)an array of the property names (keys)
Object.values(obj)an array of the values
Object.entries(obj)an array of [name, value] pairs (entries)
const prices = { apple: 12, pear: 15, plum: 8 }
Object.keys(prices) // ['apple', 'pear', 'plum']
Object.values(prices) // [12, 15, 8]
Object.entries(prices) // [['apple', 12], ['pear', 15], ['plum', 8]]

Most often you go through entries with a for…of loop. Each pair is destructured right away into two variables – and you choose their names (fruit, price) yourself again:

for (const [fruit, price] of Object.entries(prices)) {
console.log(`${fruit} costs ${price} cents`)
}
// apple costs 12 cents
// pear costs 15 cents
// plum costs 8 cents

A few more handy things:

Object.keys(prices).length // 3 – the number of properties
Object.keys({}).length === 0 // true – that's how to recognise an empty object
'apple' in prices // true – does the object have the property 'apple'?
Object.hasOwn(prices, 'banana') // false – the same another way: does it have 'banana'?
Object.fromEntries([['a', 1], ['b', 2]]) // { a: 1, b: 2 } – the opposite of entries: pairs back to an object

When you want to change all the values of an object, go through entries and build the result in a new object. Array methods like map and filter come in the next lesson; then you'll be able to write it more briefly.

// Raise every price by 10 %
const result = {}
for (const [fruit, price] of Object.entries(prices)) {
result[fruit] = Math.round(price * 1.1) // the property name is in the variable fruit → brackets
}
// result = { apple: 13, pear: 17, plum: 9 }
Demo

Object lab

What you see: The user object and buttons with operations. For each one you see the code, an explanation and the result.

Try it:

  1. Compare dot and brackets: brackets can read a property whose name is in a variable.
  2. Click destructuring: city was renamed to town and the missing email got a default value.
  3. Click rest and spread. Rest removes a property, spread overwrites or adds one – both create a new object.
  4. Go through keys, values and entries – three views of the same object.

The takeaway: An object can be read with a dot or with brackets, unpacked with destructuring, copied with spread and turned into an array with Object.entries.

Loading the interactive part…

7. An object as a dictionary

So far every object described one thing – a user, an order, a book. But an object can also serve as a dictionary. In a dictionary you find the word you're looking for on the left and read its meaning on the right. In an object the left side is the key (what you look up) and the right side is the value (what you get) – and you look up with square brackets, because the word you're looking for is in a variable.

Translating one value into another

Picture an online shop: the order status is stored as a short code ('new', 'paid', 'shipped') and on the page you want to show a readable label. The dictionary for it looks like this:

const STATUS_LABELS = {
new: 'New order', // key 'new' → value 'New order'
paid: 'Paid',
shipped: 'On its way',
}
const status = 'paid' // the order status, say from the server
STATUS_LABELS[status] // 'Paid' – finds the key 'paid' and returns its value
STATUS_LABELS['lost'] // undefined – there's no such key in the dictionary

The name in capitals is just a habit: it says this is a fixed table that doesn't change while the program runs. So that the function doesn't return undefined for an unknown status, you add ?? – “if there's nothing on the left, take what's on the right” (more in lesson JavaScript 06). Compare it with a chain of conditions doing the same:

// ❌ A chain of conditions – every new status means another line with if
function statusLabel(status) {
if (status === 'new') return 'New order'
if (status === 'paid') return 'Paid'
if (status === 'shipped') return 'On its way'
return 'Unknown status'
}
// ✅ A dictionary – a new status = a new line in the dictionary, the function stays the same
const statusLabel = (status) => STATUS_LABELS[status] ?? 'Unknown status'
statusLabel('paid') // 'Paid'
statusLabel('lost') // 'Unknown status'

Counting occurrences

A dictionary can also be filled as you go. You want to count votes: the key will be the answer, the value the count. You start with an empty object and add one for every vote:

const votes = ['yes', 'no', 'yes', 'yes']
const counts = {}
for (const v of votes) {
counts[v] = (counts[v] ?? 0) + 1
// (counts[v] ?? 0) = the count so far, or 0 when this answer isn't in the dictionary yet
}
// step by step:
// 'yes' → counts['yes'] isn't there yet → 0 + 1 → { yes: 1 }
// 'no' → counts['no'] isn't there yet → 0 + 1 → { yes: 1, no: 1 }
// 'yes' → counts['yes'] is 1 → 1 + 1 → { yes: 2, no: 1 }
// 'yes' → counts['yes'] is 2 → 2 + 1 → { yes: 3, no: 1 }
counts // { yes: 3, no: 1 }

Looking up by id

You have users in an array and often need to find the one with a certain id. Instead of going through the whole array every time, you build a dictionary once, where the key is the id and the value is the whole user. Then you find anyone with a single read:

const users = [{ id: 7, name: 'Anna' }, { id: 9, name: 'Peter' }]
const usersById = {}
for (const u of users) {
usersById[u.id] = u // store the whole user under the key id
}
// usersById = { 7: { id: 7, name: 'Anna' }, 9: { id: 9, name: 'Peter' } }
usersById[9] // { id: 9, name: 'Peter' }
usersById[9].name // 'Peter'

Check yourself

Quiz const key = 'city'. How do you read the property whose name is in the variable key?
Quiz What is the result of { ...{ a: 1, b: 2 }, b: 3 }?
Quiz const { name: userName } = user. Which variable is created?
Quiz const copy = { ...user }; copy.address.city = 'Boston'. Does user.address.city change?

Warm-up

Challenge

Business card

Warm-up

Read two properties of an object and make a copy of it with one extra property.

Task is in the comments in the code below – at the top of the file and at the places marked TODO.

Loading the interactive part…

Challenge

Challenge

Object tools

MediumBonus · free after sign-in

Six small functions for working with a user account, a form, a basket and a price list. For each one, a comment in the code says what it's good for, shows how it's used and points to the part of the lesson that explains how.

🔓 Bonus challenge – free after sign-in

Medium and hard challenges unlock once you sign in. Like the whole course, they are free – just an e-mail, no password and no payment.

How we handle your data

Summary

  • A dot when you know the property name, brackets when it's in a variable.
  • A missing property is undefined, but reading from undefined crashes – ?. helps.
  • Shorthand { name } and computed key { [field]: value }.
  • Destructuring can rename (name: n), give a default value (= 'guest') and collect the rest (...rest).
  • Spread makes a shallow copy; properties written later win.
  • Object.keys / values / entries turn an object into an array, fromEntries turns it back.
  • An object as a dictionary replaces a chain of if/else and can count occurrences or look up by id.