Javascript Objects: Iteration, Destructuring, Spread & Rest Explained with Examples


Working with objects is at the heart of modern Javascript development. Whether you're manipulating API responses, organising user data, or building powerful, dynamic web applications, understanding how to iterate over objects, destructure their properties, and harness the spread/rest operators can take your code from "functional" to "elegant."
The thing isβobjects aren't like arrays. They don't come with built-in indexing, and they have their own quirks when it comes to iteration, property access, and manipulation. If you've ever wondered when to use for...in
versus Object.keys()
, how destructuring can make your code cleaner, or why the spread operator feels like magic, this deep dive is for you.
In this article, we'll break down the different ways to work with object properties, explore safe and efficient patterns for iteration, learn how to extract data with destructuring, and see how spread/rest syntax can supercharge your object workflows. Along the way, we'll sprinkle in practical examples, performance tips, and a few "gotchas" to keep you out of trouble. π
π Iterating Over Objects
When working with objects in Javascript, iterating over their properties is a common task, but it works differently than with arrays.
They don't come with built-in indexing or iteration mechanisms. So, when you loop through object properties, the approach you choose matters β both for readability and performance.
for...in
β Old but Flexible
The for...in
loop, which we have briefly looked up in Control Structures in Javascript: Steering Your Code Like a Pro, enumerates all enumerable properties, including inherited ones (from the prototype chain). This means it can give you more than you expect. Also, while powerful, it's risky and slower for large datasets.
const user = { name: "Luna", age: 28 };
for (const key in user) {
if (Object.hasOwn(user, key)) {
console.log(key, user[key]);
}
}
Why the
Object.hasOwn
check? It ensures we only iterate over the object's own properties, not inherited ones.When to use? This is primarily the case when you need to include inherited properties intentionally. Otherwise, there are safer and more precise options.
Object.keys
, Object.values
, and Object.entries
β Modern & Safer
These methods give you direct access to an object's own properties, making them cleaner and more predictable.
These methods extract data first and then let you iterate using array methods or for...of
.
Object.keys(user).forEach(key => console.log(key)); // name, age
Object.values(user).forEach(value => console.log(value)); // "Luna", 28
for (const [key, value] of Object.entries(user)) {
console.log(`${key}: ${value}`); // name: Luna, age: 28
}
Object.keys
β Returns an array of property names.Object.values
β Returns an array of property values.Object.entries
β Returns an array of[key, value]
pairs, perfect for destructuring in loops.
Why for...of
Doesn't Work Directly on Objects
Objects are not iterable by default, so this will fail:
const user = { name: "Luna", age: 28 };
for (const item of user) {
// β TypeError: user is not iterable
}
But you can pair for...of
with Object.entries
to iterate smoothly:
for (const [key, value] of Object.entries(user)) {
console.log(key, value);
}
This approach is fast and expressive because for...of
is optimised for iterables in modern Javascript engines.
Filtering Properties Efficiently
When working with external data (e.g., API responses), you may want to filter out specific properties. Sometimes, you only need certain properties. Javascript makes this easy with Object.entries
and Object.fromEntries
:
const data = { id: 1, name: "Luna", password: "secret" };
const safeData = Object.fromEntries(
Object.entries(data).filter(([key]) => key !== "password")
);
console.log(safeData); // { id: 1, name: "Luna" }
This approach is straightforward and avoids manual loops, making it great for working with APIs or sanitising objects.
What happens here?
Object.entries(data)
This takes our data object and turns it into an array of key-value pairs:
[
["id", 1],
["name", "Luna"],
["password", "secret"]
]
.filter(([key]) => key !== "password")
Here, we're using the filter
method β an array method that lets us select only certain items based on a condition.
In this case, we're keeping only the entries where the key is not
"password"
.Note: We'll explore
.filter()
in detail in our article on arrays, so for now, remember it's a way to pick only the elements we want.
Object.fromEntries(...)
This takes our filtered array of key-value pairs and converts it back into an object.
After filtering, our array becomes:
[
["id", 1],
["name", "Luna"]
]
Converting it back gives us:
{ id: 1, name: "Luna" }
Result:
We end up with a "safe" version of our object that excludes sensitive information like passwords β perfect for sending clean data to a front-end or API.
A Quick Note on Performance
For everyday objects, all these methods perform well enough β pick what's clearest and safest.
For huge objects (thousands of properties),
Object.keys
with a classicfor
loop can be slightly faster because it avoids creating callbacks for each iteration.When performance really matters, consider using Maps data structure instead of objects β they're optimised for frequent iteration and updates.
π§© Object Destructuring Basics
Object destructuring lets us unpack properties from objects directly into variables. It's one of those Javascript features that feels magical once you get the hang of it. β¨
Basic Destructuring
Without destructuring, accessing properties can get repetitive:
const user = { name: "Luna", age: 28 };
const name = user.name;
const age = user.age;
console.log(name, age); // Luna 28
With destructuring, we can write the same thing more cleanly:
const { name, age } = user;
console.log(name, age); // Luna 28
{ name, age }
β tells Javascript: "Find these keys in the object and assign their values to variables with the same names."Cleaner, shorter, and much easier to read.
Providing Defaults
What if a property doesn't exist in the object? Without defaults, destructuring will return undefined
:
const { role } = user;
console.log(role); // undefined
We can provide fallback values using =
:
const { role = "guest" } = user;
console.log(role); // "guest"
This is great for optional data (e.g., user roles, settings, or API responses that may not always include specific fields).
Renaming Variables
Sometimes you want the variable name to be different from the property name (to avoid conflicts or make it more descriptive):
const { name: fullName } = user;
console.log(fullName); // Luna
Here:
name: fullName
β read the propertyname
but store it in a variable calledfullName
.
Gotchas & Best Practices
Typos don't throw errors.
const { nmae } = user;
console.log(nmae); // undefined π¬
Always double-check property names β destructuring silently returns undefined
for missing keys.
Avoid deep nesting
const { address: { city } } = user;
This works, but it breaks if the address
is missing (Cannot destructure property city
).
Consider using optional chaining or flattening your data structure for better results.
Don't mutate shared objects unintentionally.
Destructuring copies the values, not the object. If you modify nested objects, changes affect the original. For safe copies, use cloning (we'll cover that in later articles about advanced Objects).
Use const
for destructured variables.
const { name, age } = user;
Keeps variables predictable and avoids accidental reassignment.
π Spread and Rest with Objects
The spread (...
) and rest (...
) operators work beautifully with objects, giving us powerful ways to copy, merge, and exclude properties.
Copying Objects with Spread
The spread operator creates a shallow copy of an object:
const user = { name: "Luna", age: 28 };
const copy = { ...user };
console.log(copy); // { name: "Luna", age: 28 }
Why use spread instead of =
?
const alias = user;
alias.age = 30;
console.log(user.age); // 30 π±
Assignments don't copy objects; they copy references. Modifying alias
changes user
. Spread(β¦
) avoids this by making a new object (but still shallow β nested objects aren't cloned).
Merging Objects
Spread(β¦
) can also merge multiple objects:
const defaults = { role: "guest", theme: "light" };
const settings = { theme: "dark" };
const merged = { ...defaults, ...settings };
console.log(merged); // { role: "guest", theme: "dark" }
Order matters: later spreads overwrite earlier ones.
Perfect for configuration objects or combining API data.
Rest(β¦
) Syntax to Exclude Keys
Sometimes you want everything except a few properties. Rest syntax makes this easy:
const userProfile = { id: 1, name: "Luna", password: "secret" };
const { password, ...safeProfile } = userProfile;
console.log(safeProfile); // { id: 1, name: "Luna" }
Excellent for sanitising objects (e.g., removing sensitive data before sending to the front-end).
Performance Tips
For small to medium objects, spread/rest is perfect β it's concise and readable.
For huge objects or frequent merges, mutating a new object manually can be slightly faster, but readability usually wins in everyday projects.
π§ͺ Practical Example: Putting It All Together
Let's combine everything we've learned about accessing, modifying, and destructuring objects into one clean example.
const product = {
id: 101,
name: "Coffee Mug",
price: 9.99,
metadata: {
color: "black",
inStock: true
}
};
// Access properties
console.log(product.name);
// Add and update
product.discount = 0.2;
product.price = 8.99;
// Destructure
const { name: title, price, metadata: { inStock } } = product;
console.log(`${title} - $${price} - Available: ${inStock}`);
Step-by-Step Breakdown
1. Creating the Object
We define a product
object with keys like id
, name
, price
, and a nested metadata
object. This kind of structure mirrors real-world data β like a product in an e-commerce system.
2. Accessing Properties
console.log(product.name);
Dot notation is clean and readable for known keys.
If we used
product["name"]
, it would achieve the same result β but bracket notation shines when property names are dynamic or not valid identifiers.
3. Adding and Updating Properties
product.discount = 0.2; // Adding a new property
product.price = 8.99; // Updating an existing property
Objects in Javascript are dynamic β you can add or modify properties anytime.
Gotcha: Modifying the object here affects all references to it, since objects are passed by reference.
4. Destructuring with Renaming and Nested Access
const { name: title, price, metadata: { inStock } } = product;
name: title
β grabsproduct.name
but stores it astitle
.metadata: { inStock }
β dives into the nestedmetadata
object and extracts theinStock
property.price
β directly pulls the price property.
This approach is cleaner than writing:
const title = product.name;
const price = product.price;
const inStock = product.metadata.inStock;
5. Using the Extracted Values
console.log(`${title} - $${price} - Available: ${inStock}`);
This prints something like:
Coffee Mug - $8.99 - Available: true
Why This Matters
This simple example shows why objects are essential:
They keep data organised (everything about the product lives in one place).
They're dynamic (you can add discounts, update prices).
They're expressive (destructuring makes your code shorter and more readable).
Best Practices Highlighted
Use dot notation for most cases, but switch to bracket notation for dynamic keys.
Avoid unnecessary mutations by cloning when needed (we'll explore this in future articles on Objects).
Use destructuring to make your code more declarative and avoid repetitive property access.
Keep nested objects manageable β deeply nested destructuring can hurt readability.
Wrapping Up: Objects Are Just the Beginning
We've covered a lot of ground here β from creating objects and accessing their properties to modifying them, checking for keys, looping through their data, and even making our code cleaner with destructuring and shorthand tricks. π―
Objects are the backbone of Javascript. They're how we structure data, model real-world entities, and build more complex applications.
But believe it or not, we've only scratched the surface. There's a whole world of advanced object concepts β prototypes, inheritance, getters and setters, immutability, and design patterns β waiting for us to explore. π
But before we take that deep dive into advanced Javascript concepts, we need to visit Javascript Arrays and then something that brings our code to life: the DOM (Document Object Model).
So, take a breather, let this sink in, and get ready β next up, we'll step into the Javascript Arrays β¨
Subscribe to my newsletter
Read articles from Sangy K directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Sangy K
Sangy K
An Introvert Coder | Trying to be a Full-stack Developer | A Wannabe Content Creator