A Practical Guide to ES6 Destructuring

What is destructing?

There’s a new way to assign variables in ES6, and it’s called destructuring. If your familiar with Perl or Python, this is nothing new, but if all you know is JavaScript, then saddle up.

Instead of assigning a single variable at once, like var a = ‘apple’; destructuring lets you assign multiple variables at once. The simplest example of this is var [a,b,c] = ['apple','orange','banana'];

In the example above we’ve assigned the variables on the left to the values of the array on the right. Visually it looks like the variables a, b, c are inside an array, but they’re actually not, this is just what the destructing syntax looks like. The two examples below are equivalent.

var [a,b,c] = ['apple','orange','banana'];
// is equivalent to:
var arr = ['apple','orange','banana'];
var a = arr[0];
var b = arr[1];
var c = arr[2];

Destructuring also works with objects. The only difference is that we use curly brackets on on the left instead of square brackets.

var {a,b} = {a:'apple', b:'orange'};
// is equivalent to: 
var obj = {a:'apple', b:'orange'};
var a = obj.a;
var b = obj.b;

Here we’ve assigned the variables a and b to the properties a and b of an object.

If the object we’re assigning from has more properties, they will be ignored in the assignment. Destructuring just picks out the properties you declare on the left. For var {a,b} = {a:’apple’, b:’orange’, c:’banana’}; a still returns ‘apple’, b still returns ‘orange’ and the rest of the properties are ignored. Using an array like this will return the same results var [a,b] = ['apple','orange','banana'];.

But what if you want to assign b and c from the array and skip a? You can do that, but the syntax is a little odd. You remove the variable name but keep the comma, setting b and c looks like this var [,b,c] = ['apple', 'orange', 'banana']; and setting just c looks like this var [,,c] = ['apple', 'orange', 'banana'];.

When assigning with objects, your variable names don’t have to equal the object property names. var {a:aVar, b:bVar} = {a:’apple’, b:’orange’}; assigns the variables aVar and bVar to the properties a and b on the right.

But what happens when the property doesn’t exist? The variables are undefined, like you would expect.

var {c,d} = {a:'apple', b:'orange'};
// c -> undefined
// d -> undefined
// because {a:'apple', b:'orange'} doesn't contain properties named c or d

Luckily, destructuring also provides the option of assigning default values, so that if the property value is null or undefined, the variable will use that value instead.

var {c='asparagus',d='broccoli'} = {a:'apple', b:'orange'};
// c -> 'pineapple'
// d -> 'tomatoe'

Default values can also be combined with custom named variables.

var {c:myC='asparagus',d:myD='broccoli'} = {a:'apple', b:'orange'};
// myC -> 'asparagus'
// myD -> 'broccoli'

So those are the basics, now when is this stuff actually useful?

Practical Applications of Destructuring

Variable Assignment Shortcuts

For DOM properties

For legibility purposes, it’s common to create variables to hold the values of long DOM object properties. Destructuring makes these declarations even shorter.
In ES5

var rect = getBoundingClientRect(),
top = rect.top,
left = rect.left,
width = rect.width; 
height = rect.height; 

With Destructuring

var {top, left, width, height} = getBoundingClientRect();
// or with custom named variables
var {myTop:top, myLeft:left, myWidth:width, myHeight:height} = getBoundingClientRect();

getBoundingClientRect() returns an object with some properties, so you can use destructuring to assign variables to those properties. Date.now() does the same thing.

var {year, month, day} = Date.now();

For Regular Expressions

var url = 'https://developer.mozilla.org/en-US/Web/JavaScript';
var parsedURL = /^(\w+)\:\/\/([^\/]+)\/(.*)$/.exec(url);
var [, protocol, fullhost, fullpath] = parsedURL;

Regular expressions can return an array of results from groups (groups the parts of the regex that are in between round brackets, like (\w+) ), so if you expect the groups to return something specific, you can assign them using destructuring too.

For Fallback Values

In ES5, if you want to provide a fallback value for a variable, you would do something like this

var obj = {a:'apple', b:'orange'};
var c = obj.c || 'fallback value';
// c -> 'fallback value'

With destructuring, you can do this instead.

var {c='fallback value'} = {a:'apple', b:'orange'};
// c -> 'fallback value'
// or with a custom named variable
var {c:myC='fallback value'} = {a:'apple', b:'orange'};
// myC -> 'fallback value'

Destructuring in function parameters

The lack of named function parameters in JS a constant annoyance. It’s hard to create optional arguments, and you always have to be mindful of the order of the parameters you pass to a function. With destructuring, you can fake this functionality pretty easily, and even add default argument values to the mix.

In ES5, a nice way of mimicking named function parameters was to pass in an object as the parameter, and then extract the properties of the object into variables like this.

function foo(obj){
    var a = obj.a; 
    var b = obj.b;
};
foo({a:'apple', b:'orange'});

In the above example, the function parameter obj is assigned to the value {a:'apple', b:'orange'}, if this were a variable declaration, it would look like this obj = {a:'apple', b:'orange'}

In ES6, we can use destructuring to greatly shorten this pattern.

function foo({a, b}){
    // vars a and b are ready to use!
};
foo({a:'apple', b:'orange'});

In this example, the assignment is analogous to {a, b} = {a:'apple', b:'orange’}, which takes advantage of destructuring.

Providing fallback values

In our function foo example, it was also very common to provide default values for arguments like this.

function foo(obj){
    var a = obj.a || 'fallback value'; 
    var b = obj.b || 'fallback value';
};
foo({a:'apple', b:'orange'});

We can achieve the equivalent using destructuring with default values.

function foo({a='default value', b='default value'}){
    // vars a and b are ready to use!
    // and if they aren't set, they will fallback to their default values
    console.log(a,b);
};
foo({a:'apple'});
-> 'apple', 'default value'