ES6 introduced a new feature called destructuring. To better understand it let’s look into the basics of javascript objects.To add single property to an object we use a dot notation.
1 2 3 |
var user = {}; user.name = 'John doe' user.age = '25' |
By the nature of dot notation we can add properties one at a time. To extract property we need to use the same syntax . If we want to add multiple properties to an object we need to use object literal notation during time of initialisation
1 2 3 4 |
var user = { name : 'John doe', age: '25' } |
We have a way to add multiple properties at a time but we do not have a way to exact multiple properties at a time until destructuring was introduced in es6 .
So as object literals allows us to add multiple properties in an object, destructuring allows us to extract multiple properties from an object. This reduces the amount of code we have to write dramatically using destructuring
1 2 3 4 5 |
var user = { name: 'john doe', age: '25', email: 'johndoe@gmail.com' } |
Before destructuring
1 2 3 |
var name = user.name //prints john doe var age = user.age //prints 25 var email = user.email //prints johndeo@gmail.com |
Using destructuring
1 |
var {name, age, email} = user; |
They both create and initialise 3 variables name, age and email.
Another feature of destructuring is that we can destructure the result of function invocation
1 2 3 4 5 6 7 |
function getUser() { return { name: 'john doe', age: '25', email: 'johndoe@gmail.com' }; } |
Rather than invoking “getUser” and grabbing all the properties off it one by one we could use destructuring
1 2 3 4 5 |
var {name, age, email} = getUser(); name //prints john doe age //prints 25 email //prints johndoe@gmail.com |
Why is destructuring important?
It provides a quicker and neater way to assign values:
Consider a scenario where we have data of stores in an object to be shown on a map.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
const result = { responseType: 'discounts', id: '10533019bf4938538cef383481538a4b', locations: { city: 'UNION CITY', distance: 4.521417621024534, lat: 40.77651180000001, lng: -74.0255827, state: 'NJ', street: '4012 BERGENLINE AVE', url: '/benefits-discounts/', zip: '07087', catCode: 10004 } }; function displayMarkersOnMap(result) { console.log('Type of response,' + result.responseType); // Type of response discounts console.log('latitude ' + (result.locations.lat)); // latitude 40.77651180000001 console.log('longitude ' + (result.locations.lng)); // longitude -74.0255827 console.log('cityname' + (result.locations.city)); //cityname UNION CITY } displayMarkersOnMap (result); |
We can achieve the result from above code but there are a few cautions to be taken care of – we can easily make a typo , instead of writing locations we can write location which will give undefined and again if the object is deeply nested, the chain to access the inner values become longer and more code has to be written which makes the coding complex and expensive. With destructuring we can shorten the code, make it less complex and more readable.
1 2 3 4 5 6 7 8 |
function displayMarkersOnMap({ responseType, locations: { lat = 0, lng = 0, city = 0 } }) { console.log('Type of response' + responseType); console.log('latitude ' + lat); console.log('longitude' + lng); console.log('cityname' + city); } displayMarkersOnMap(result); |
Another Example:
We often use axios to do a HTTP request to get data from services. It returns the following object:
1 2 3 4 5 6 7 8 |
{ data : {}, status:200, statusText: 'OK', headers:{}, configs:{}, requests:{} } |
Data gives us the response provided by the server. Consider a scenario where we need to get data of all the users we would use axios
1 |
const request = await axios.get('getuser/user'); |
Request object will have the same structure as shown above . To get the data provided by the server we would get request.data. Suppose we want to get data for a particular user with an id= 1730 which needs to be passed in the request getuser/user/:userId and it returns an array .To extract data we can do request.data[0]
We can also use destructuring here :
1 2 3 |
const { data } = await axios.get('getuser/user') console.log(data); // [{username: 'john doe'}] |
How to destructure properly?
Suppose we have an object
1 2 3 |
const person = { name: 'John Doe' } |
Destructuring it –
1 |
const { name } = person || {} |
We need to add or empty object {} because destructuring throws error if the value is undefined or null as we shown in example :
1 2 |
let name = undefined; const { personName } = name; |
This will throw an error –
Uncaught TypeError: Cannot destructure property ‘personName’ of ‘name’ as it is undefined.
But if we set it to an empty object
1 2 |
name = undefined || {} const { personName } = name //it gives undefined |
Another example:
1 2 3 4 5 6 7 8 |
const object = { name: { details: { title: 'john doe', description: 'loreum ipsam loreum oupsim' } } } |
1 |
const { name: { details: { title } } } = object || {} |
Name is within object, details is within name and finally title is destructured from details. We are assigning a variable named title for title. This works untill all the properties in the object exists and none of them are undefined or null. We can deal with undefined by setting defaults value.
1 2 3 4 5 6 7 |
const personDetails = { name: 'John doe', } const { name = 'defaultName', age = 21 } = personDetails; console.log(name); // John doe console.log(age); //21 |
Providing default values using destructuring works if variable is either undefined or doesn’t exist. All other values like null, false, 0 are not dealt by setting default values.
1 2 3 |
const personDetails = { name: undefined } const { name = 'John doe'} = personDetails; console.log(name) // John doe |
while for null:
1 2 3 4 |
const personDetails = { name: null } const { name = 'John doe'} = personDetails; console.log(name) //null |
ARRAY DESTRUCTURING
1 |
var user = ['john doe','john@gmail.com','hyderabad'] |
To identify each item in the array we need to create variable for each item
1 2 3 |
let name = user[0], email = user[1], place = user[2]; |
This can be tedious. Using destructuring we can more effectively extract items from the array
1 |
var [name, email, place] = user; |
PRACTICAL USES OF DESTRUCTURING IN JAVASCRIPT
1. Nested array and Objects
1 2 3 4 5 6 7 8 9 10 11 12 13 |
let user = { level : 'associate', paid: true, professionalDetails: { id: 123455, level: 2 personalDetails : { name : 'john', age : 25, gender: male } } } |
1 2 3 4 5 6 7 8 9 10 |
let name = user.professionalDetails.personalDetails.name, age = user.professionalDetails.personalDetails.age, gender = user.professionalDetails.personalDetails.gender; //We can also save user.professionalDetails.personalDetails in a variable let details = user.ProfessionalDetails.PersonalDetails; let name = details.name, age = details.age, gender = details.gender |
Still this will be a lot of work. To simply it we can use destructuring –
1 |
let {name, age, gender} = user.professionalDetails.personalDetails |
Using this name prints john , age prints 25 and gender prints male.
Destructuring helps to break complex code into simpler code. It makes the code less complex and cleaner.
2.Naming functional arguments
Suppose we have a function which accepts multiple parameters
1 2 3 |
getFilterData = (userType, category, publishedDate, language, author) => { } |
Whenever another developer uses this function he has to take care of 2 things – the order in which arguments are passed and read documentation to filter out the arguments he doesn’t need.
1 |
getFilterData('active-user','category1','05-07','English','john'); |
For simplifying it we can pass parameters as Objects and use destructuring so that we don’t need to worry about the order of the parameters and ignore the arguments we do not want.
1 2 3 4 5 6 7 8 9 10 11 12 |
//option1 getFilterData = ({userType, category, publishedDate, language, author}) => { } //option2 getFilterData({ category:'category1', language:'English', userType:'active-member', publishedDate:'05-07', author:'John' }); |
Even if the order in which the parameters are sent are not the same, the function will know which parameter is associated with which value.We can also ignore the arguments we don’t want into consideration
1 2 3 4 5 |
getFilterData({ userType:'active-member', publishedDate:'05-07', author:'John' }); |
CONCLUSION – Destructuring simplifies the code complexity and makes the code cleaner and readable. It works great with complex functions which have a lot of parameters and default states. Destructuring makes it easier to read and use the code as it breaks down the complex object . It also increases performance as we use variables and use them multiple times.