I've written previously about some of my favorite features of ES2015 (formerly known as ES6). If you have read those, you probably know that I really like string interpolation, block-scoped variables, and context-preserving arrow functions. But one feature which I have not used until now is object and array destructuring.
Destructuring is a very concise and readable way to extract parts of arrays or objects. It is not necessary all the time, but sometimes it can make you code cleaner and more readable.
Destructuring Objects
Traditionally in JavaScript, if you wanted to extract values from an object you would do something like this:
// first, we have an object whose data we want to extract
var myObj = {
name: 'Ryan',
age: '30',
color: 'green'
};
// next, we extract the values one by one
var n = myObj.name;
var a = myObj.age;
var c = myObj.color;
// we can now do whatever we need to do with those variables
console.log(n, a, c);
Now, obviously, we don't always need to extract values into their own variables. But if you need to manipulate those values in some way, you generally will extract them rather than writing myObj.something
over and over again. In this case, please assume there is a reason that we need to extract the values into their own variables.
Destructuring allows us to accomplish the same thing, just in a more concise manner.
let myObj = {
name: 'Ryan',
age: '30',
color: 'green'
};
// next, we extract the values at once using destructuring
let {name: n, age: a, color: c} = myObj;
// we can now do whatever we need to do with those variables
console.log(n, a, c);
There you go! We got the values out like before, but this time we did it using destructuring rather than individually extracting them.
Destructuring Arrays
If you understand destructuring Objects, then you can probably already guess how destructuring arrays works.
Traditionally, you would do this:
// first, we have an array whose data we want to extract
var myArr = [
'value1',
'value2',
'value3'
];
// next, we extract the values one by one
var first = myArr[0];
var second = myArr[1];
var third = myArr[2];
// we can now do whatever we need to do with those variables
console.log(first, second, third);
Using destructuring, we can extract the values like this:
// first, we have an array whose data we want to extract
let myArr = [
'value1',
'value2',
'value3'
];
// next, we extract the values at once using destructuring
let [first, second, third] = myArr;
// we can now do whatever we need to do with those variables
console.log(first, second, third);
So, as you can see, we declared our variables inside square brackets and it extracted the first item in the array into the first variable, the second into the next variable, and so on. Order matters when destructuring arrays!
One Use Case
As I said earlier, I knew about variable assignment using destructuring, but I have not until now really found a use case where it made a lot of sense to use, especially for destructuring arrays. But with the project I am currently working on, I am pulling data from the Facebook Page Graph API.
Using the API, I can make calls to Facebook and get an object back with a page's public data. I am using it to get information about businesses. It sends back a JavaScript object with the requested data. A response might look like this (depending on which fields you requested).
let demonstratedResponse = {
name: 'My Business Name',
about: 'We are a business... isn't that exciting!',
phone: '(123) 456-7890'
hours: {
fri_1_open: '8:00',
fri_1_close: '12:00',
fri_2_open: '13:00',
fri_2_close: '18:00',
sat_1_open: '8:00',
sat_1_close: '17:00'
}
};
I could use object destructuring if I wanted to here, but I really don't need to extract multiple value into their own variables, so it's not worth my time to bother. But notice those hours. Facebook has stored information for each day's hours in each key in the hours object (e.g. fri_1_open
). Facebook allows two different time ranges per day, in this case it looks like the business takes an hour off at lunch time on Fridays.
Looking at each key, we see what the day is, the hours range (whether 1 or 2), and the type (open or close). I don't want to store the hours in my data object like that. I want to extract those values into objects which I can then read. I want my hours data to look like this:
let hours = {
fri: {
open1: '8:00',
close1: '12:00'
},
// and so on
}
This is a perfect use case for destructuring!
Traditionally, I would get the data like this:
// this is my simulated response from Facebook
var demonstratedResponse = {
name: 'My Business Name',
about: 'We are a business... isn\'t that exciting!',
phone: '(123) 456-7890',
hours: {
fri_1_open: '8:00',
fri_1_close: '12:00',
fri_2_open: '13:00',
fri_2_close: '18:00',
sat_1_open: '8:00',
sat_1_close: '17:00'
}
};
// this is my default hours object which I want to populate w/ data from Facebook
var myHours = {
sun: {},
mon: {},
tue: {},
wed: {},
thu: {},
fri: {},
sat: {}
};
var fbHours = demonstratedResponse.hours;
var keys = Object.keys(fbHours);
// define variables which I'll be using in the for loop
var splitKey, day, num, time;
// loop through each key in the hours object from FB
for (var i = 0; i < keys.length; i++) {
// first, I split the key into an array
splitKey = keys[i].split('_');
// next, I extract the values
day = splitKey[0];
num = splitKey[1];
type = splitKey[2];
// then, I add them to my object
myHours[day][type + num] = fbHours[keys[i]];
}
console.log(myHours);
The Facebook API guarantees me (at least in the current version) that I can always expect my hours data to look like this. That's why I can safely grab the first three values from the array and know what they are (day, type, etc.). But now I am going to write this using ES2015 and array destructuring.
// this is my simulated response from Facebook
const demonstratedResponse = {
name: 'My Business Name',
about: 'We are a business... isn\'t that exciting!',
phone: '(123) 456-7890',
hours: {
fri_1_open: '8:00',
fri_1_close: '12:00',
fri_2_open: '13:00',
fri_2_close: '18:00',
sat_1_open: '8:00',
sat_1_close: '17:00'
}
};
// this is my default hours object which I want to populate w/ data from Facebook
let myHours = {
sun: {},
mon: {},
tue: {},
wed: {},
thu: {},
fri: {},
sat: {}
};
let fbHours = demonstratedResponse.hours;
// loop through each key in the hours object from FB
// I am using 'let' so the variables are block-scoped
// and don't need to be declared outside of the loop
for(let key of Object.keys(fbHours)) {
// first, I split the key into an array
let splitKey = key.split('_');
// next, I extract the values using destructuring
let [day, num, type] = splitKey;
// then, I add them to my object
myHours[day][type + num] = fbHours[key];
}
console.log(myHours);
Using ES2015 in general allows me to write this in a more clean and concise way. But notice in particular the line: let [day, num, type] = splitKey;
. That is very straightforward and allows you to extract those values without the repetition necessary when extracting them individually. In this case, I always know what indexes 0
, 1
, and 2
are going to be in the split array, so this is a beautiful use case for destructuring.
Conclusion
So, in conclusion, use destructuring! Or do not use destructuring. It is up to you. I find that my code is much more concise and readable using ES2015 in general, and using destructuring for use cases like above. But, let me warn you, many features of ES2015 are still not natively supported in browsers and in Node. In my current case, I am building an application using the Meteor framework, which automatically transpiles my code from ES2015 to ES5 so it is compatible with nearly all browsers. But if you are not using a framework which does all that work automatically for you, you will need to use a transpiler like Babel.
But, while ES2015 is not natively run everywhere, the fact of the matter is that it is the future. So, you might as well get comfortable using the new syntax now!