Demystifying destructuring in JavaScript: A look into object & array destructuring
Using destructuring for extracting values easily from complex data structures in JS
Destructuring is a JavaScript expression introduced in ES6 that makes it easier to extract properties and elements from objects and arrays respectively, makes our code simpler, shorter, cleaner, and more reusable. We can do a bunch of useful stuff with destructuring that we’ll uncover in this lesson.
Object Destructuring
We’ll start with destructuring objects. Let’s say you have a User object having some properties and you want to extract the properties of the user into distinct variables.
Now, generally, you’d use the dot(.) operator or square brackets([ ]) to access the object properties.
Often, you’ll find this pattern very repetitive and more so for objects with a higher number of properties. Destructuring provides syntactic sugar to extract properties from objects into distinct variables like this:
const user = {
id: 1,
name: 'Sreejit',
age: 22
}
//without destructuring
const id = user.id;
const name = user.name;
const age = user.age;
//with destructuring
const { id, name, age } = user;
Now, id will be the same as user.id, name the same as user.name, and so on. That’s how easy it is to avoid repetitive patterns for extracting object properties with destructuring.
Assigning a different name to properties
In the above example we saw that for destructuring, the variable name had to be the same as the property name of the Object (id was matched to user.id). But let’s say you want to use a different variable name for storing a property of the object. Well, you can do it like this with destructuring:
const user = {
id: 1,
name: 'Sreejit',
age: 22
}
//custom variable name for storing object properties
const { id: userId, name : userName, age: userAge } = user;
Now, userId will be matched to user.id, userName to user.name, and so on.
Extracting properties that are invalid JS identifiers
With this, you can extract property names from objects which are not valid JS identifiers and assign them to a valid variable name like this:
const user = {
id: 1,
"user-name": "Sreejit",
age: 22
}
const { "user-name" : userName } = user;
Providing default values
Now, let’s say you want to extract some property from an object but you’re dealing with an unknown object so you’re not sure whether that property exists on that object or not. So in case, the property doesn’t exist on that object, you want to assign a default value to that variable. With destructuring, you can easily do it like this:
const user = {
id: 1,
name: 'Sreejit',
age: 22
}
//providing a default value to properties
const { id, imageUrl = 'placeholder.jpg' } = user;
Now, imageUrl will be set to the default value ‘placeholder.jpg’ in case user.imageUrl is undefined (which is the case for us). This feature can be useful for such a use case where you want to use a default image in case the user doesn’t have an image.
Destructuring nested objects
Sometimes, we might have to deal with nested objects and extract properties from them.
Generally, we’d have to create a property chain to extract properties from nested objects. Destructuring provides us an easier syntax to extract properties from nested objects like this:
//extracting values from nested objects
const user = {
id: 1,
basicInfo: {
name: "Sreejit",
age: 22
}
}
//without destructuring
const name = user.basicInfo.name;
const age = user.basicInfo.age;
//with destructuring
const {
basicInfo: { name, age }
} = user;
Like this, the variables name and age will hold the values of user.basicInfo.name & user.basicInfo.age respectively. Much easier & cleaner than property chaining!
Assigning different name to nested object properties
Just like how you can assign a separate name to properties while extracting them from objects, you can do the same while extracting properties from nested objects too.
const user = {
id: 1,
basicInfo: {
name: "Sreejit",
age: 22
}
}
//assigning custom name to properties extracted from nested objects
const {
basicInfo: { name : userName, age: userAge }
} = user;
Now, userName would be mapped to user.basicInfo.name and userAge would be mapped to user.basicInfo.age, like that.
Destructuring object passed as a param
In some cases, you might want to pass an object as a parameter to some function, then access some or all of the object properties inside that function. Destructuring makes it easy for you.
const user = {
id: 1,
name: "Sreejit",
age: 22
}
//without destructuring
function printUserDetails(user) {
console.log("I am " + user.name + ", my age is " + user.age);
}
//with destructuring
function printUserDetails({ name, age }) {
console.log("I am " + name + ", my age is " + age);
}
You might not notice it much because this is a relatively small and simple example, but you’ll really appreciate this in the case of larger objects and more complex operations inside functions.
Passing default values to function parameters
As shown before about how to assign default values to properties while destructuring, while passing an object as a parameter to a function, you can pass on a default value for any property of the object in case the object property doesn’t exist or is undefined.
const user = {
id: 1,
name: "Sreejit",
age: 22
}
//passing default value for object properties
function printUserDetails({ name, age, balance = 0 }) {
console.log("User balance: " + balance);
}
printUserDetails(user); //output: User balance: 0
Accessing the rest of the object with destructuring
With ES6 rest operator(...) and destructuring, you can easily access and store some part of an object and use it where needed.
Suppose you have a user object from which you want to extract only a selected number of properties and store the other properties together inside a single object. You can do so with destructuring & using the rest operator like this -
const user = {
id: 1,
name: "Sreejit",
age: 22,
balance: 450,
imageUrl: "user.jpg"
}
//storing rest of an object with destructuring
const { id, imageUrl, ...restOfUser } = user;
/*
restOfUser = {
name: "Sreejit",
age: 22,
balance: 450
}
*/
One important thing to remember here is that the rest operator must be placed on the last element while destructuring any object.
Iterating through complex objects with destructuring
A lot of times, you might come across a scenario where you need to loop through an array of objects or even nested objects. Extracting properties from an array of objects/ nested objects can be repetitive and complex, destructuring makes it easy and simple.
Let’s take a look at this example where you might want to iterate through a list of your projects. We’ll take a look at how to do easy for-of iteration through an array of nested objects easily with destructuring.
This example might look somewhat complex, but it’s really easy to understand once you get familiar with the pattern of destructuring.
const projects = [
{
title: "To-do list",
description: "A simple to-do list creation app",
techStack: {
frontEnd: "React",
backEnd: "Node.js"
}
},
{
title: "Recipe App",
description: "An app to find a bunch of delicious recipes",
techStack: {
frontEnd: "Angular",
backEnd: "Java"
}
},
];
//easy for-of iteration through nested objects with destructuring:-
for(const {title, techStack: { frontEnd: fE, backEnd: bE }} of projects){
console.log("I made a " + title + " app with frontend: " + fE + " and backend: " + bE);
}
//output:
//I made a To-do list app with frontend: React and backend: Node.js
//I made a Recipe App app with frontend: Angular and backend: Java
You can use this with functional programming as well when methods like using .map() or .filter() on an array of nested objects, destructuring will probably save you a lot of repetitive work!
Array destructuring
We looked at multiple patterns and use-cases for destructuring objects. Now let’s move our attention to destructuring arrays in JS and extracting elements from an array with it.
For accessing array elements, we need to access them with their indices. Destructuring also uses indices to extract array elements, but in a shorter way:
const socialMedias = ["Facebook", "Twitter", "LinkedIn"];
//without destructuring
const socialOne = socialMedias[0];
const socialTwo = socialMedias[1];
const socialThree = socialMedias[2];
//with destructuring
const [socialOne, socialTwo, socialThree] = socialMedias;
As an array index starts at 0, the first element in the LHS will be mapped to the array element at index 0, the 2nd element to the array element at index 1, and so on.
Assigning default values to array elements with destructuring
We can provide default values to array elements (just like how we did for object properties) with destructuring, in case the particular index doesn’t exist in the array, it’ll have the default value!
//assigning default values to array elements with destructuring
const [e0, e1 = 5] = [8];
console.log(e1); // 5
const [e0, e1 = 5] = [8, 9];
console.log(e1); // 9
Swapping variables with array destructuring
Destructuring arrays and accessing elements like this provides us a cool way to swap variables in JS 😎 We can swap two elements by destructuring an array of the two elements:
let a = 1, b = 2;
//swapping made easy with destructuring
[a, b] = [b, a];
console.log(a, b); // 2 1
Accessing only specific indices of an array
Suppose, you don’t need to extract all entries from an array, and you want to skip extracting the unwanted elements. You can do so with destructuring by skipping specific indices like this:
const naturalNumbers = [1, 2, 3, 4, 5];
//extracting elements at specific indices only
const [a,,b,,c] = naturalNumbers;
console.log(a, b, c); //1 3 5
Notice the extra commas (,) used to skip over elements at specific indices. We skipped extracting elements at indices 1 & 3 in the above example! (Array index starts at 0)
Accessing the rest of the array
Like you can extract the rest of an object using destructuring and the ES6 rest operator (...), you can do the same with arrays to extract the rest of an array, like this:
const naturalNumbers = [1, 2, 3, 4, 5];
//extracting rest of an array
const [,, ...restofNaturalNumbers] = naturalNumbers;
console.log(restofNaturalNumbers); //[3, 4, 5]
One important thing to remember here is that the rest operator must be placed on the last element while destructuring an array. Trying to pick the rest from the beginning or middle of an array won’t work, unfortunately!
Combining object and array destructuring
Now that we have learnt so much about object & array destructuring, how about we check out a use case where we can combine both for extracting values from some complex data structure?
Let’s say you are given a list of users and their 3 favourite electronics brands, and you want to access the 3rd favourite brand of each user. You can do it like this using destructuring easily:
const users = [
{
name: "John",
favouriteBrands: ["Apple","Samsung","Sony"]
},
{
name: "Doe",
favouriteBrands: ["JBL","Apple","Dell"]
}
]
//making use of both array & object destructuring for extracting values
for(const { name, favouriteBrands:[,,thirdFavouriteBrand] } of users){
console.log(name +"'s 3rd favourite electronic brand is "+ thirdFavouriteBrand);
}
//output:
//John's 3rd favourite electronic brand is Sony
//Doe's 3rd favourite electronic brand is Dell
This might not be a very practical example, but you might face a similar scenario for handling other complex data structures and extracting values from them where this practice might come in handy!
Also, this might look a bit complex initially, but once again, it's just about getting familiar with the destructuring pattern, and then it'll look very simple for you!
Ending notes
Hopefully, you learnt many things about destructuring in JS, and will be able to apply this concept to make your code shorter, simpler and less repetitive! ES6 ftw!
While trying to be more regular at sharing my learnings with this beautiful community on my blog, I'm also active on LinkedIn & Twitter, so let's connect and keep the mutual learning going! Cheers, and see you all real soon! 👋