This lesson connects several things you’ve already seen:
const [users, setUsers] = useState([]);
and:
const { name, age } = user;
and React props such as:
<User name="John" age={30} />
The goal is to understand how JavaScript objects work and how we extract, copy, and pass their data around.
1. JavaScript objects
An object is a collection of properties:
const user = { id: 1, name: "John", age: 30, active: true};
Think of it as:
user | +-- id β 1 +-- name β "John" +-- age β 30 +-- active β true
Access properties:
user.name; // "John"user.age; // 30user.active; // true
You can also use bracket notation:
user["name"];
These are equivalent when the property name is known.
2. Dot notation vs bracket notation
This works:
const user = { name: "John"};console.log(user.name);
But bracket notation becomes particularly useful when the property name is stored in a variable:
const property = "name";console.log(user[property]);
Result:
John
This would not work the same way:
user.property;
because that looks for a property literally called "property".
3. Objects can contain functions
For example:
const user = { name: "John", greet() { console.log("Hello"); }};
Call it:
user.greet();
The function is a property of the object.
When a function belongs to an object like this, we commonly call it a method.
4. Objects can contain anything
An object can contain:
const user = { id: 1, name: "John", active: true, roles: ["admin", "editor"], address: { city: "Kochi", country: "India" }, greet() { console.log("Hello"); }};
So you can have:
object βββ primitive βββ array βββ object βββ function
This is why JavaScript objects are extremely flexible.
5. Object destructuring
Now the first very important ES6 feature.
Suppose:
const user = { id: 1, name: "John", age: 30};
You could write:
const name = user.name;const age = user.age;
But destructuring allows:
const { name, age } = user;
This means:
const name = user.name;const age = user.age;
Conceptually, yes.
So:
const { name, age } = user;
means:
Take the `name` property from user βput it into variable `name`Take the `age` property from user βput it into variable `age`
6. Array destructuring vs object destructuring
This is one of the most important distinctions from the previous lessons.
Array
const numbers = [10, 20];const [a, b] = numbers;
Destructuring is based on position:
numbers[0] β anumbers[1] β b
Object
const user = { name: "John", age: 30};const { name, age } = user;
Destructuring is based on property name:
user.name β nameuser.age β age
So:
Array destructuring β positionObject destructuring β property name
This distinction should become automatic.
7. Rename while destructuring
Suppose:
const user = { name: "John", age: 30};
You don’t have to name your variable name.
You can do:
const { name: userName, age: userAge } = user;
Now:
userName; // "John"userAge; // 30
Read this as:
name property β variable userNameage property β variable userAge
This syntax looks strange initially, but you’ll see it in real React and Node code.
8. Default values in destructuring
Suppose:
const user = { name: "John"};
You can write:
const { name, age = 30 } = user;
Now:
name; // "John"age; // 30
The default is used only when the property is undefined.
9. Nested destructuring
Given:
const user = { name: "John", address: { city: "Kochi", country: "India" }};
You can do:
const { name, address: { city, country }} = user;
Now:
name; // "John"city; // "Kochi"country; // "India"
This is useful, but don’t overuse deep destructuring. Very complex destructuring can become harder to read than ordinary property access.
10. Function parameters can be destructured
This is very common in React.
Instead of:
function User(props) { return <h2>{props.name}</h2>;}
you can write:
function User({ name }) { return <h2>{name}</h2>;}
The second form says:
The function receives an object, and I want its
nameproperty.
Suppose React effectively gives:
{ name: "John", age: 30}
Then:
function User({ name }) {
extracts:
name = "John";
This is one of the reasons you see React code full of { ... } around function parameters.
11. useState vs props: two different destructuring styles
Now compare these:
const [users, setUsers] = useState([]);
and:
function User({ name, age }) {}
The first is array destructuring:
position 0 β usersposition 1 β setUsers
The second is object destructuring:
name property β nameage property β age
This is a very important React distinction.
12. Spread syntax with objects
Let’s revisit spread:
const user = { name: "John", age: 30};const copy = { ...user};
Now:
copy
contains:
{ name: "John", age: 30}
The spread operator copies the object’s own enumerable properties into a new object.
At a beginner level, think:
“Take the properties from this object and put them into a new object.”
13. Updating an object using spread
Suppose:
const user = { name: "John", age: 30};
We want:
same userbut age = 31
Write:
const updatedUser = { ...user, age: 31};
Result:
{ name: "John", age: 31}
Why does age: 31 win?
Object properties appearing later overwrite earlier properties with the same key.
So conceptually:
...user βname: Johnage: 30age: 31 βoverwrite age
14. This is common in React state updates
Suppose:
const [user, setUser] = useState({ name: "John", age: 30});
To change just the age:
setUser({ ...user, age: 31});
We don’t do:
user.age = 31;
for normal React state updates.
Instead, we create a new object.
Conceptually:
old object β{ name: "John", age: 30 } ...copy...new object β{ name: "John", age: 31 }
This gives React a new object reference.
We’ll later connect this directly to the question you raised previously about why React cares about new references.
15. Spread with arrays
Given:
const users = ["John", "Jane"];
Append without modifying the original:
const newUsers = [...users, "Mike"];
Result:
["John", "Jane", "Mike"]
Prepend:
const newUsers = ["Mike", ...users];
Result:
["Mike", "John", "Jane"]
Merge:
const first = [1, 2];const second = [3, 4];const combined = [...first, ...second];
Result:
[1, 2, 3, 4]
16. Spread is shallow
This is an important interview topic.
Consider:
const user = { name: "John", address: { city: "Kochi" }};const copy = { ...user};
copy is a new object.
But:
copy.address === user.address
is:
true
Why?
Because spread creates a shallow copy.
The outer object is new, but nested objects are still shared.
Visualize:
user βββββββββββββββββ βcopy βββββββββββββββββ€ β address { city: "Kochi" }
Both objects point to the same nested address object.
This becomes extremely important when we talk about immutable state.
17. Deep copy is a different problem
Don’t assume:
const copy = { ...user };
means:
“Everything inside user has been recursively copied.”
It hasn’t.
For modern applications there are several strategies for deep cloning, but don’t jump to one automatically. Often you don’t actually need a deep clone.
For React state, it’s usually better to create new references only along the part of the structure you’re changing.
For example:
const updatedUser = { ...user, address: { ...user.address, city: "Bengaluru" }};
Now both the outer object and changed nested object are new references.
18. Object shorthand
ES6 gives us convenient syntax here:
const name = "John";const age = 30;const user = { name, age};
Instead of:
const user = { name: name, age: age};
JavaScript understands that:
name
means:
name: name
when used in an object literal.
You’ll see this everywhere.
19. Computed property names
You can dynamically create a property name:
const field = "name";const user = { [field]: "John"};
Result:
{ name: "John"}
Another example:
const field = "email";const value = "john@example.com";const user = { [field]: value};
Result:
{ email: "john@example.com"}
This is useful when dynamically building objects.
20. this – the important part
Now we reach one of JavaScript’s most confusing concepts for Ruby developers:
this
Consider:
const user = { name: "John", greet() { console.log(this.name); }};user.greet();
Output:
John
Here:
this
refers to the object used to call the method:
user.greet();
So conceptually:
user.greet() βthis = user
Therefore:
this.name
is:
user.name
21. A critical difference from Ruby
In Ruby, you may mentally think:
“
selfis the current object.”
JavaScript’s this is more nuanced.
One of the most useful rules:
For a normal function call,
thisis determined by how the function is called, not simply where the function was defined.
That means:
user.greet();
and:
const greet = user.greet;greet();
can have different this behavior.
This is one of the reasons JavaScript’s this can be tricky.
22. Arrow functions and this
Arrow functions behave differently.
They do not create their own this.
Consider:
const user = { name: "John", greet: () => { console.log(this.name); }};user.greet();
Do not assume:
this = user
just because the function appears inside the object.
That is not how arrow functions work.
This is one of the reasons you should not blindly replace every regular function with an arrow function.
We’ll spend an entire lesson on this, call, apply, bind, and arrow-function behavior.
23. Object references
Now an important JavaScript behavior.
const user1 = { name: "John"};const user2 = user1;
We did not create a new object.
Both variables refer to the same object:
user1 ββββββ β { name: "John" } βuser2 ββββββ
Therefore:
user2.name = "Jane";console.log(user1.name);
prints:
Jane
This is because objects are reference values.
24. Compare primitive values
Now compare:
let a = 10;let b = a;b = 20;console.log(a);
Result:
10
For the primitive number:
a β 10b β 10then:b β 20
Changing b doesn’t alter a.
With objects:
user1 βββ β object βuser2 βββ
Both references point to the same object.
This distinction will become crucial when we discuss:
- React state
- equality
- immutability
- shallow comparison
useMemouseCallback
25. === with objects
This gives us another important interview question.
const user1 = { name: "John" };const user2 = { name: "John" };console.log(user1 === user2);
Result:
false
Why?
Because these are two different objects.
Even though their contents are identical:
user1 β Object Auser2 β Object B
They have different references.
But:
const user1 = { name: "John" };const user2 = user1;user1 === user2;
returns:
true
because both reference the same object.
26. This explains something important in React
Later you’ll see code like:
setUsers(users);
versus:
setUsers([...users]);
The first gives React the same array reference.
The second creates a new array:
users ββββββββ old array[...users] βββ new array
This distinction becomes important because React can use reference identity when determining whether state/props values changed.
We’ll go deep into this when we revisit React state and rendering.
27. Complete React example
Let’s put today’s concepts together.
function User({ user }) { const { name, age } = user; return ( <div> <h2>{name}</h2> <p>{age}</p> </div> );}
Here we have:
Object parameter
{ user }
Object destructuring
const { name, age } = user;
Function
function User(...) {}
And React passes an object as the argument.
28. Another React example
Suppose:
const [user, setUser] = useState({ name: "John", age: 30, city: "Kochi"});
Update only the city:
setUser({ ...user, city: "Bengaluru"});
This combines:
object+spread+new object reference+state update
And now you can see why learning JavaScript first is useful.
π§ The five concepts to remember
At the end of this lesson, these should be clear:
1. Object destructuring
const { name, age } = user;
Means:
const name = user.name;const age = user.age;
2. Array destructuring
const [first, second] = numbers;
Means:
const first = numbers[0];const second = numbers[1];
3. Spread
const copy = { ...user };
Creates a new shallow object.
4. References
const b = a;
with objects means both variables refer to the same object.
5. this
For a normal method call:
user.greet();
this inside the method refers to the receiver of that call – user.
Arrow functions have different this behavior.
π― Int. questions
Try answering these before reading further.
Q1
What’s the difference?
const [a, b] = [10, 20];
and:
const { a, b } = { a: 10, b: 20 };
Q2
What does this produce?
const user = { name: "John", age: 30};const { name: userName } = user;
Q3
What is the difference between:
const user2 = user1;
and:
const user2 = { ...user1 };
Q4
What happens here?
const user1 = { name: "John" };const user2 = { name: "John" };console.log(user1 === user2);
Q5
What does this do?
const user = { name: "John", age: 30};const updated = { ...user, age: 31};
Q6
Why can this be dangerous to assume?
const copy = { ...user };
when user contains nested objects?
π§ͺ Live coding practice
Problem 1 – Destructure
Given:
const user = { id: 10, name: "John", age: 30};
Extract:
idnameage
using object destructuring.
Problem 2 – Rename
Extract name into a variable called:
userName
Problem 3 – Update immutably
Given:
const user = { name: "John", age: 30};
Create a new object where:
name = "Jane"
without modifying user.
Problem 4 – Add a property
Given:
const user = { name: "John"};
Create:
{ name: "John", active: true}
using spread.
Problem 5 – Nested object
Given:
const user = { name: "John", address: { city: "Kochi", country: "India" }};
Create a new object where only:
city = "Bengaluru"
changes.
Don’t mutate the original nested address.
Problem 6 – Reference test
Predict:
const a = { count: 1 };const b = a;b.count = 2;console.log(a.count);
Then compare:
const a = { count: 1 };const b = { ...a };b.count = 2;console.log(a.count);
Explain why the outputs differ.
π How this connects to your React learning
You now have almost all the JavaScript pieces needed to understand this:
const [users, setUsers] = useState([]);
and:
function User({ name, age }) {
and:
setUser({ ...user, age: 31});
They are no longer “React syntax”. They are combinations of ordinary JavaScript:
useState(...) β function call[users, setUsers] β array destructuring{ name, age } β object destructuring...user β spreaduser => ... β function / callback
That’s exactly the mental model we want.
Next lesson
Lesson 6 – this, call, apply, bind, arrow functions, and closures.
This is the first lesson where JavaScript will behave noticeably differently from Ruby, and it is especially important for understanding React event handlers and Node.js code.