Hello there!
For a long time now I've been wanting to take notes on a couple of tricks I currently use at work regarding the concept of Destructuring in JavaScript. I feel like most of the things I learn and am currently using in a daily basis will just fade out once I stop using them this often. Thus, I decided to write down those things in order to make them stick with me for longer even when I'm not looking at them daily. I used to do this when in middle and high school but stopped right after I started college and I feel the consequences now, specially considering I have a really shaky memory.
For those out there who are not familiar with the idea of destructuring in JavaScript, following is a brief overview of it. There are also tons of posts about it if you google it, so feel free to look for more content if this is too brief or not clear enough for you ;)
Destructuring was not always there in JavaScript for people to use, the concept was introduced to the language in June of 2015 together with a few other features that make up the 6th edition of the language, which is popularly known as ES6 or ES2015 (check this for reference).
The idea is basically to allow assignment of variables based on object properties or array values in a prettier manner. If you think of it as being the opposite idea of structuring something, which it is, you'll get that the object is being "broken down" into pieces until you find the value you want and then use that to create a variable.
Check the following code which shows one of the ways you would create a variable that is supposed to have a value contained in an object considering you don't know the existence of destructuring.
Note that classs
is written like that in the entire text to avoid conflicts with the keyword class
.
const homoSapiens = {
kingdom: 'Animalia',
classs: 'Mammalia',
family: 'Hominidae',
genus: 'Homo',
species: 'H. sapiens'
}
const homoSapiensFamily = homoSapiens.family;
// and if you want to be certain of the type of the variable, you would
// set a default value for it in case the `family` property does not
// exist in the source object
const safeHomoSapiensFamily = homoSapiens.family || '';
You see that you'd have to do the same thing for each property that you want to use in that object, which is not really a huge pain to do but why should we do it that way when we can take advantage of the power of destructuring to both create variables and make sure of their type?
The following is a snippet that uses destructuring to accomplish the same.
const { family = '', species = '' } = homoSapiens;
Here we are creating two variables called family
and species
based on properties that have the same name in the source object. And we are also making sure that they will be strings even when those two properties are not contained in the object.
You might argue that family
and species
are not really meaningful variable names if you look at them by themselves. Destructuring also allows us to specify the variable name (an alias) we want instead of using the name of the property in the object.
const {
family: homoSapiensFamily = '',
species: homoSapiensSpecies = ''
} = homoSapiens;
Here we use the same values as before but now we're creating two variables called homoSapiensFamily
and homoSapiensSpecies
. Much more meaningful, right?
If you got the idea by now I believe you noticed you can go crazy about it and destructure real nested objects.
const homoSapiens = {
classs: {
name: 'Mammalia',
super: {
name: 'Tetrapoda'
},
sub: {
name: 'Theria'
}
},
species: 'H. sapiens'
};
const {
classs: {
super: {
name: homoSapiensSuperClass = ''
}
}
} = homoSapiens;
Here we created a variable named homoSapiensSuperClass
which will have the value of Tetrapoda
.
What if we try to destructure a nested object and at some point the property we specified does not exist?
// considering the previous homoSapiens object
const {
classs: {
infra: {
name: homoSapiensInfraClass = ''
}
}
} = homoSapiens;
If you try this you'll see that we get an error that says:
Uncaught TypeError: Cannot destructure property `name` of 'undefined' or 'null'.
This happens because in the source object we don't really have an object called infra
under the classs
object. Thus, the homoSapiensInfraClass
variable is never defined.
To avoid this you can set a default value for each property you are going through while destructuring an object. In this specific case, you would want to make sure that the default value for that infra
property is an object, so you can keep destructuring it in case that property does not exist.
const {
classs: {
infra: {
name: homoSapiensInfraClass = ''
} = {}
} = {}
} = homoSapiens;
This way even though the homoSapiens
object does not contain a property called infra
you will still end up defining a variable called homoSapiensInfraClass
which will receive the default value you set or undefined
if you did not set a default value for it.
It also works with arrays!
The idea is basically the same with arrays, the difference, apart from the fact that syntax is a bit different, is that you cannot consider property names and instead will do things based on the order of items in the array.
const [first, second ] = ['a', 'b'];
// first will be 'a' and second will be 'b'
// you can also set default values
const [safeFirst = 'a', safeSecond = 'b'] = ['a']
// safeSecond here will have a value of 'b'
It also works in a function signature!
You can also do destructuring in a function signature in order to expose only specific properties of the object being received to the function context.
const homoSapiens = {
kingdom: 'Animalia',
classs: 'Mammalia',
family: 'Hominidae',
genus: 'Homo',
species: 'H. sapiens'
}
function logSpeciesInfo ({ species = '', kingdom = '', classs = '' }) {
console.log(`The species ${species} belongs to the ${kingdom} kingdom and ${classs} class.' );
}
logSpeciesInfo(homoSapiens);
// Logs "The species H. sapiens belongs to the Animalia kingdom and Mammalia class."
Any other property from the object that is not specified in the function header does not exist within the function body.
Can I do destructuring everywhere?
There is a really cool table in the Destructuring assignment page of MDN web docs that shows the current browser compatibility of this syntax. You can see that it is widely supported so compatibility shouldn't be an issue for you, unless...IE is a thing for you :)
Quiz
With what you learned in this post, are you able to use the power of destructuring to swap values of two variables without using any extra variable? Try before looking at comments ;)
Let me know in the comments! And if you have any other use cases for destructuring make sure to share that as well :D
Thanks for reading!
Top comments (26)
You can even do this wizardry:
Yes! Dynamic destructuring!
js wizardry... That's pretty cool I haven't thought of that
It is possible to do it nested???
You mean the following?
Good article, thanks ! :)
But one moment
We have small but important difference between default value of destructed property and
||
In this case runtime compiler (as I know) checks value only on
undefined
and because of this some falsy value likefalse
or''
is not been replaced to default value"bar"
But in other case
||
checks first operand on any possible falsy value and if we have.foo
likenull
then variable will been equals to"bar"
let a = 1;
let b = 2;
[a, b] = [b, a];
=)
Nice, didn't realise one could easily use this to swap variables!
Congrats :)
I should probably tell people not to look at comments before trying π
I'd advice against deeply nested destructures like the given example:
There is
classs
there, which could be a typo and it would easily go totally unnoticed.Another point I'd like to make is that it is very hard to read the above. Just do:
Or if you want to allow all objects to miss:
Much easier to understand what is happening. If you want to get multiple items you could use array destructuring:
Although this makes sense only if you have a whole lot of those. This example is good because it retains the normal reading order, while renaming while destructuring fights against the normal reading order. Rename in destructuring should be used sparingly to keep code easy to read.
Hey Vesa, thank you for the suggestion. I appreciate your contribution.
As for your concern on legibility I would take that more as a preference matter, I personally don't see that as a very hard thing to read but I understand your point.
I think the option you gave it's nice if you want things to explicitly fail so you'd be aware of possible typos. In a context in which you don't know what to expect for the structure of the
homoSapiens
object for instance I'd prefer to be safe and set default values for each object being destructured, instead of receiving errors likeCannot read property 'x' of undefined
.And yeah, if you can use lodash then go for it ;)
I think it's by purpose.
class
is a reserved keyword. Although possible to use in some modern browser, I bet IE doesn't like this.I would agree with you. I think that just because you can doesn't necessarily mean that you should. I do appreciate the knowledge sharing though and it is interesting to see the different ways that it's possible to destructure.
You actually don't need dynamic de-structuring to swap values of two variables without using any extra variable:
Thats cool. I didn't know you could do that with the default values. It seems backwards to me though with the variable to assign from on the left of the colon and the variable to assign to on the right.
I found that slightly counterintuitive to start with, too, when you're used to
name = value
. The easiest way I find to remember the order is{ from: to } = obj
. Also, it wouldn't make much sense to use{ to: from } = obj
because you're no longer putting thefrom
in the same position as the key is in the object.A very nice explanation π
Just because it makes my inner biologist cringe: could you possible replace 'specie' with 'species' (because that's both the singular and the plural form: en.wiktionary.org/wiki/species)?
Updated! Thanks for that :D
Haha, we had the same idea this week! Nice post :)
3 Powerful Examples of Destructuring Assignment
Laurie γ» Jun 11 γ» 2 min read
Ah yeah! Great post! The more the merrier :)
I mean, itβs clearly one of the best bits of modern ES syntax. Everyone must know!
I don't know if anyone already posted this answer but from what I see must people used objects to do it instead of arrays.
My solution :
Did not know you could destructure an array. Very cool! Thanks for the post.