What is Destructuring?
Destructuring is a special really cool syntax feature in JavaScript, which lets us to extract values from arrays, objects, or other iterable structures and assign them to variables.
It's a shorthand way to access properties or elements of a data structure without having to use dot notation or array indices.
How is it beneficial for us (who write code in JavaScript)?
Destructuring has several benefits that make our code more concise, readable, and maintainable!
- Improved Readability: Destructuring simplifies code by reducing the need for complex variable assignments and dot notation.
- Less Boilerplate Code: You can extract values directly from data structures without needing to create intermediate variables.
- More Concise Code: Destructuring can reduce the number of lines of code needed to achieve the same result.
- Flexibility: You can destructure data structures of any type (objects, arrays, iterables), making it a versatile tool in your JavaScript toolkit.
Effective destructuring 🚀 enables us to write more expressive, maintainable, and efficient code that's easier to understand and debug.
Basic Example
const person = { name: 'John', age: 30 };
const { name, age } = person;
console.log(name); // "John"
console.log(age); // 30
Here we have destructured an object person
with two properties: name
and age
.
When destructuring an JavaScript object, the values we extract must be the exact same keys in the object. You can't place userName
in place of name
in the line
const { name, age } = person;
. Which simply means - const { userName, age } = person;
won't work.
But yes! We can apply aliasing while destructuring an object.
E.G. -
const person = { name: 'John', age: 30 };
const { name:userName, age:userAge } = person;
console.log(userName); // "John"
console.log(userAge); // 30
Most probably you have seen destructuring an object for the first time when you were importing a module. For example when importing the exec function -
import { exec } from "node:child_process"; // ES Module syntax
const { exec } = require("child_process"); // commonJS syntax
Similarly we can destructure arrays also -
const numbers = [4, 5, 6];
const [x, y, z] = numbers;
console.log(x); // 4
console.log(y); // 5
console.log(z); // 6
Here when destructuring arrays, you don't need to use aliasing to assign any element to a custom variable name. Because array elements are simply just values, they aren't bound with some keys.
Default Values
Destructuring allows you to assign default values to variables if the property doesn't exist in the object.
const person = { name: 'John' };
const { name = 'Anonymous', age } = person; // age will be undefined
console.log(name); // "John"
console.log(age); // undefined
Here the string value 'John'
wasn't substituted by the value 'Anonymous'
in the variable name
because it already existed in the object.
Whereas -
const person = { name: 'John' };
const { name, age = 30 } = person; // age defaults to 30 if not present
console.log(name); // "John"
console.log(age); // 30
Spread Syntax
The spread syntax or say, operator (...)
can be used with destructuring to capture remaining elements of an array or properties of an object into a new variable.
- spread syntax with Arrays -
const numbers = [1, 2, 3, 4, 5];
const [first, second, ...rest] = numbers;
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5] (remaining elements)
- spread syntax with Objects -
const person = { name: 'John', age: 30, city: 'New York' };
const { name, ...info } = person;
console.log(name); // "John"
console.log(info); // { age: 30, city: "New York"} (remaining properties)
Nested Destructuring
Destructuring can be nested to extract values from deeply nested objects or arrays.
const data = {
user: {
name: 'Alicia',
origin: 'Romania',
eyes: 'blue',
address: {
city: 'London',
}
}
};
const { user: { name, address: { city } } } = data;
console.log(name); // "Alicia"
console.log(city); // "London"
Destructuring in function parameter list
Suppose we've an JavaScript object named credentials
-
const credentials = {
name: 'Debajyati',
age: 20,
address: {
city: 'Kolkata',
state: 'West Bengal',
country: 'India'
},
phone: '',
email: '',
hobbies: ['reading', 'listening to music', 'coding', 'watching Anime'],
skills: {
programming: true,
blogging: true,
singing: false
}
}
And a function named showCredentials
which takes only 1 argument value which is an object and Standard outputs a string based on some of the object properties.
Well, we could write the function definition in this way -
function showCredential(obj) {
const hasSkill = (skill) => obj.skills[skill];
console.log(
`${obj.name} is ${obj.age} years old.\n Lives in ${obj.address.city}, ${obj.address.country}.\n`,
`He has the following hobbies: ${obj.hobbies.join(", ")}`,
);
if (hasSkill("programming")) {
console.log(`He is a programmer.`);
}
if (hasSkill("singing")) {
console.log(`He is a singer.`);
}
if (hasSkill("blogging")) {
console.log(`He is also a tech blogger.`);
}
}
Calling it with -
showCredential(credentials);
Getting this output -
Debajyati is 20 years old.
Lives in Kolkata, India.
He has the following hobbies: reading, listening to music, coding, watch
ing Anime
He is a programmer.
He is also a tech blogger.
Instead we can destructure the object argument in the parameter list while defining the function. Like this -
function showCredential({ name, age, address: { city, country}, hobbies, skills }) {
const hasSkill = (skill) => skills[skill];
console.log(
`${name} is ${age} years old.\n Lives in ${city}, ${country}.\n`,
`He has the following hobbies: ${hobbies.join(", ")}`,
);
if (hasSkill("programming")) {
console.log(`He is a programmer.`);
}
if (hasSkill("singing")) {
console.log(`He is a singer.`);
}
if (hasSkill("blogging")) {
console.log(`He is also a tech blogger.`);
}
}
which gives the same output.
📝 NOTE The function still takes only one argument. Destructuring didn't increase number of arguments in the function parameter list.
Also, calling the function didn't change as well. It still is -
showCredential(credentials);
So, Why destructure objects in Function Parameter List?
While destructuring in function arguments list may seem cumbersome or tedious at first but it has it's quite important benefits.
Important Points to Consider
- Safer Code: Destructuring can help prevent errors by making it clear which properties are expected by the function. If a property is missing in the passed object, destructuring will result in an error during function execution, aiding in early detection of potential issues.
- Reduced Verbosity: By directly extracting properties into variables within the parameter list, you avoid repetitive object property access using dot notation. This leads to cleaner and more concise function definitions.
- Focus on Functionality: By destructuring within the parameter list, you separate data access logic from the function's core functionality. This improves code organization and makes the function's purpose clearer.
Destructuring Strings
Just how we destructure arrays, similarly we can also unpack strings as array elements. A clever usage of our intelligence.
const fruit = 'grape';
const [first, second, ...rest] = fruit;
const animal = rest.join('');
console.log(animal); // ape
⚠️ Remember ! When you use the spread operator
(...)
to capture the remaining characters from a string, you don't get a string. You get an array of those characters.
Some Handy Application Examples of Destructuring
-
Destructuring for swapping without 3rd variable:
JavaScript traditionally required a temporary variable to swap the values of two variables. Destructuring offers a more concise and readable way to achieve this.-
Before Destructuring:
let a = 10; let b = 20; let temp = a; a = b; b = temp; console.log(a, b); // Output: 20 10
-
After Destructuring:
let a = 10; let b = 20; [a, b] = [b, a]; console.log(a, b); // Output: 20 10
So nifty & elegant✨! Isn't it?
-
-
Destructuring Function Return Values: Functions can return multiple values as an array or object. Destructuring allows you to unpack these returned values into separate variables, improving code clarity.
Let's suppose you have a function that fetches data from an API and returns a response object:
function getUserUpdates(id) { // Simulating some API call with a GET request return { data: { player: response.group.names[id], brain: "rotting", powerLevel: Number(response.group.power[id]), useAsDecoy: true, }, statusCode: Number(response.status), }; }
In the context of building APIs or handling server responses, it offers distinct advantages that enhance code quality and maintainability.
Accessing individual properties is going to be breeze, because you can directly extract the properties you need from the function's return value into separate variables during the function call itself.
const {
data: {player, useAsDecoy, powerLevel},
statusCode,
} = getUserUpdates(1);
Whenever a function returns an object and you are interested in specific property values, always apply destructuring straight away.
If you're still thinking destructuring in return values isn't a good idea, these 2 more advantages may convince you -
(A) Simplified Mental Model: Destructuring simplifies the thought process required to understand data flow for the developer who will be using your function. Instead of memorizing intricate property access chains, developers can focus on the meaning conveyed by the variable names used in the destructuring pattern. This reduces cognitive load and promotes better code comprehension.
(B) Reduced Boilerplate Code for Complex Return Objects:
When functions return objects with numerous or nested properties, destructuring significantly reduces the boilerplate code needed to access them individually. This leads to a more concise and less cluttered codebase, improving overall code quality.
-
Destructuring with Conditions:Destructuring can be combined with conditional statements to handle different scenarios based on the structure of an object. If you've a function that receives an object with optional properties:
function greetUser(user) { const { name = "Anonymous" } = user || {}; // Destructuring with default value console.log(`Hello, ${name}!`); } greetUser({ name: "Bob" }); // Output: "Hello, Bob!" greetUser({}); // Output: "Hello, Anonymous!" (no name property) greetUser(undefined); // Output: "Hello, Anonymous!" (function receives no argument)
Conclusion
Throughout the whole article, we've learnt that 'Destructuring' is a powerful and versatile feature in JavaScript that can significantly improve your code's readability, maintainability, and efficiency. By effectively using destructuring techniques, you can write cleaner, more concise, and less error-prone code. So, embrace destructuring and take your JavaScript skills to the next level!
If you found this POST helpful, if this blog added some value to your time and energy, please show some love by giving the article some likes and share it with your friends.
Feel free to connect with me at - Twitter, LinkedIn or GitHub :)
Happy Coding 🧑🏽💻👩🏽💻! Have a nice day ahead! 🚀
Top comments (18)
I was a huge fan of destructuring as it gives me a more concise looking code. But when things get big and many objects are destructured, everything is just losing its context. Take this example
Not mentioning if you have a colliding property names then you have to make an alias for the colliding property name so you would still ended up in a messy code
Understood! I shall keep this in mind.
When using the
spread
syntax to copy objects that havenested properties
, it is crucial to understand how JavaScript handlesreferences
to thesenested properties
. Thespread operator
creates ashallow copy
of the object. This means that while the top-level properties are copied, any nested objects or arrays are stillreferenced
from the original object. Consequently, changes tonested properties
in thecopied object
will also reflect in theoriginal object
and vice versa.Let's take an example:
Here, we define an object
person
with properties likename
,age
andaddress
. Andaddress
object containscity
andzip
.Shallow Copy with Spread Operator
The spread operator
{ ...person }
creates a shallow copy ofperson
. This means that the top-level properties(name, age, and address)
are copied directly intopersonCopy
. However, sinceaddress
is anobject
(a nested property), only thereference
to this object is copied, not theactual nested object itself
.Modifying Nested Property
Since
personCopy.address
is areference
to the sameaddress
object asperson.address
, changingpersonCopy.address.city
to'Los Angeles'
affects bothperson
andpersonCopy
. Hence, bothconsole.log
statements output"Los Angeles"
.Modifying Nested Property Again
Similarly, when we change
person.address.city
back to'New York'
, it also affectspersonCopy.address.city
because theyreference
the sameaddress
object. As a result, bothconsole.log
statements output"New York"
.Massive! That's a brief write up! I learnt something new.
Thank you 😊!
Really well-explained!!
Thanks a lot for your positive feedback! I’m always looking to improve.
Thank you for your detailed feedback! Pleased to know that you found the guide comprehensive and the examples clear. Looking forward to bringing you more useful content!
And hey!
Thanks again 🙃 for your support!
Great article!!
Would love to know the performance overhead of destructuring. As js devs, we don't really care abt minor performance issue, but still it would be interesting to know.
Thank you for your kind words. You asked so I did a quick research on this topic.
I didn't actually thought about the performance consideration before. Well, it is indeed a critical point to think about.
Well as I far as I realised, Destructuring in JavaScript does introduce a slight performance overhead compared to traditional property access (dot notation) due to the extra steps involved in creating and assigning variables. In scenarios where performance is critical, this overhead can become noticeable.
For instance:
There could be more examples. But I think these are enough.
But for most practical purposes, the performance difference is negligible and should not deter you from using destructuring.
As you have been developing applications in JavaScript long before I started, you might know all of this better than I do.
This is amazing, I should also consider writing.
Thank you so much! 😊
Writing is incredibly rewarding, and I'd love to see what you come up with. Let me know if you need any suggestions on getting started, don't hesitate to reach out!
I'd love to read what you write—go for it!
awesome :)
Thank u for the appreciation :)
Well explained... It was really helpful for me
Thank you! It’s great to hear that you've found the explanation helpful!
Great! Loved it
All the lightbulbs went off above my head when you tied destructing and imports. Thank you!!!!
😊 🙌 😊 🙌