Two commonly used data structures in JavaScript are Object
and Array
. And many times we may need to extract individual pieces of the object instead of the whole thing. This is where Destructuring comes in.
Destructuring is a special syntax which is used to "destructure" or "unpack" an object or array into many variables, as that may be more useful.
Array destructuring
Here's an example of array destructuring:
const site = ['dev', 'to'];
// destructuring here
let [domain, ext] = site;
// this is basically equal to
// let domain = site[0]
// let ext = site[1]
alert(domain); //=> dev
alert(ext); //=> to
By using destructuring, we did not have to repeat the array's name or the indices. Destructuring can be really helpful when using string methods which return arrays:
const [firstName, lastName] = 'John Doe'.split(' ');
const [full, short] = /(.+?(?!=day))day/gi.exec('Monday');
Note that the original array does not change when destructuring. Destructuring is not destructive.
Skippping items
You can use holes to skip items in arrays:
const [, lastName] = 'John Doe'.split(' ');
alert(lastName); //=> Doe
Works with any iterables
Actually, we can use any iterable in destructuring (including objects, which we will talk about later)
let [a, b, c] = 'abc'; //=> ['a', 'b', 'c']
let [one, two, three] = new Set([1, 2, 3]);
This is because destructuring is kind of syntactic sugar of using for...of
over the Iterable and then assigning the value to variables.
Assign anything
You can assign anything which can be assigned, say object properties:
const day = {};
[day.full, day.short] = /(.+?(?!=day))day/gi.exec('Monday');
Or even existing variables:
let full, short;
[full, short] = /(.+?(?!=day))day/gi.exec('Monday');
The variable swapping trick
There's a common trick which is used to swap two variables using destructuring:
let student = 'You';
let master = 'Me';
[student, master] = [master, student];
student; //=> Me
master; //=> You
// The student has become the master
The rest ...
If an array is longer than what you destructure, the extra items are left out.
const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
const [day1, day2] = days;
day1; //=> Sunday
day2; //=> Monday
// No more assignments
You can collect those items using rest parameters:
const days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
const [
day1, // First item aka Sunday
day2, // Second item aka Sunday
...restDays // All the other items
] = days;
restDays; //=> ['Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
You can use any name instead of restDays
, the only rule is that it should be preceded by three dots and should be last.
Default values
If you destructure nonexistent values, there will be no error. The items will simply be undefined. We can set default values to fix this:
const [name = 'Anonymous'] = [];
name; //=> Anonymous
const [name = 'Anonymous'] = ['John'];
name; //=> John
Nesting
You can also destructure nested arrays. Just use the same syntax inside.
const arr = [["John"]]; // Nested array!
const [[name]] = arr;
name; //=> 'John'
Or a really complex example:
const arr = ['Foo', ['Bar', ['Baz', 'Lol', ['Quux']]]];
const [foo, [bar, [baz, lol, [quux]]]] = arr2;
foo; //=> Foo
bar; //=> Bar
baz; //=> Baz
lol; //=> Lol
quux; //=> Quux
Just note that when you destructure nested items which dont exist, an error will be thrown.
Object destructuring
Objects can also be destructured and the syntax is pretty much the same.
const site = {domain: 'dev', ext: 'to'};
// destructuring here, note the {}
let {domain, ext} = site;
// this is basically equal to
// let domain = site.domain
// let ext = site.ext
alert(domain); //=> dev
alert(ext); //=> to
Also note the order does not matter:
const rectangle = {
width: 10,
height: 20,
x: 5,
y: 5
};
// All of these work
const {width, height, x, y} = rectangle;
const {x, width, height, y} = rectangle;
const {y, width, x, height} = rectangle;
// ...
Aliasing
We can set aliases to destructured variables by writing realName: alias
just like a normal object:
const rectangle = {
width: 10,
height: 20,
x: 5,
y: 5
};
const {width: w, height: h, x, y} = rectangle;
w; //=> 10 (value of width)
h; //=> 20 (value of height)
Just like in arrays, we can set defaults:
const name = {first = prompt('First name'), last = prompt('Last name')} = {first: 'John'};
We can even mix default values and aliases:
const name = {first: f = prompt('First name'), last: l = prompt('Last name')} = {first: 'John'};
The rest ...
Just like arrays, objects also can have a rest property.
const coords = {x: 13, y: 42, z: 8};
const {x, ...rest} = coords;
x; //=> 13
y; //=> {y: 42, z: 8}
A quick gotcha for assigning existing values
In the previous examples, we used let {...} = {...}
which is fine. But when you try {...} = {...}
there will be an error:
let width, height;
// Error here
{width, height} = {width: 10, height: 21};
this is because JavaScript considers {...}
on it's own as a block statement. A block statement can be used to group code:
{ // This is a isolated block
let foo = 42;
alert(foo);
}
So, to tell JavaScript that we need destructuring, we can wrap it in ()
:
let width, height;
// This is fine
({width, height} = {width: 10, height: 21});
Nesting
Just like in arrays, we can destructure nested properties too! We just need to mimic the structure of the source
const rect = {
color: red,
coords: {
x: 12,
y: 7,
}
};
const {
color,
coords: {
x,
y,
}
} = rect;
color; //=> red
x; //=> 12
y; //=> 7
// No coords :(
Note that we have no coords, since we are destructuring it's values.
Here's a complete destructuring example:
const order = {
items: ['Pizza', 'Donuts'],
extra: true,
amount: {
pizza: 2,
donuts: 4
}
};
const {
items: [main, ...rest] = [], // Array destructuring
extra = false, // Default props
amount: { // Nested
pizza,
donuts
},
homeDelivery = false, // Non existent values
} = order;
That's everything you need to know about destructuring!
If you found this post helpful, spread the word! or follow me on twitter or over here to stay updated on my blog posts!