Andrew Hill

@andrewjrhill

Getting to Grips with ES6: Destructuring

Part IV: Understanding destructuring - referencing and defaults.

You can view previous parts of this series here.

Preface

This article is designed as a “get started” read for beginner to intermediate developers who wish to gain a better understanding of Destructuring introduced in EcmaScript 6 (ES6).

As part of my “Getting to Grips with ES6” series, I aim to create a reference containing straight forward explanations ordered in short sections to help us understand and apply these concepts directly to our current development processes.

Each article builds on concepts learned in previous articles. For this reason, you may want to consider taking a look at a previous article if you encounter a new concept you do not recognize.

Written by Andrew Hill
You can find me on LinkedIn, Twitter, Instagram, and GitHub.

Destructuring

The Destructuring Assignment Syntax allows us to quickly extract data from an array or an object and assign that data to any given variable.

Referencing Object Values the Traditional Way

The following example illustrates how one might reference object data before the advent of ES6 and destructuring:

var city = {
name: 'Cape Town',
population: 987007,
website: 'capetown.gov.za',
};
var name = city.name;
var population = city.population;
var website = city.website;
console.log(name, population, website);
// Output: "Cape Town 987007 capetown.gov.za"
Example 1: Referencing object values using a more traditional approach.

This pattern of potentially needing to save references to values from the same object leads to repetitive, less concise code.

Referencing Values Through Destructuring

ES6 destructuring allows us to achieve the same result with a much more concise syntax. We can rewrite the first example as follows:

const city = {
name: 'Cape Town',
population: 987007,
website: 'capetown.gov.za',
};
const { name, population, website } = city; 
console.log(name, population, website);
// Output: "Cape Town 987007 capetown.gov.za"
Example 2: A cleaner, more concise way to reference object values through destructuring.

Using destructuring, only a single variable declaration is needed to define all top level variables in the city object.

We also have the ability to destructure arrays in ES6. The only difference being, when destructuring an array, we need to use square brackets instead of curly braces:

const city = ['Cape Town', 987007, 'capetown.gov.za'];
const [name, population, website] = city;
console.log(name, population, website);
// Output: "Cape Town 987007 capetown.gov.za"
Example 3: Referencing array values through destructuring.

You may at times find yourself faced with a object that is misrepresented by unintuitive key value pairs. Let us consider the following as an example of a dataset that we are retrieving via a very poorly written API:

const city = {
x: 'Cape Town',
y: 987007,
z: 'capetown.gov.za',
};
const { x, y, z } = city;
const cityWithCountry = `${x}, South Africa`
console.log(cityWithCountry);
// Output: "Cape Town, South Africa"
Example 4: A poorly designed dataset with nondescript keys reduces our code readability.

The nondescript identifiers in this dataset will ultimately lead to code that is very difficult to read and maintain, especially if left uncommented.

Assuming we are unable to modify the initial city object keys, the data can effectively be “renamed” (referenced) through destructuring, improving code readability:

const city = {
x: 'Cape Town',
y: '987007',
z: 'capetown.gov.za',
};
const {
x: name,
y: population,
z: website} = city;
const area = `${name}, South Africa` console.log(area);
// Output: "Cape Town, South Africa"
Example 5: Code readability is improved by renaming object keys through destructuring.

Destructuring Deeply Nested Values

Interestingly, destructuring is not limited to top level values of an object or an array. We can access deeply nested values by following the same destructuring pattern:

const city = {
name: 'Cape Town',
population: 987007,
website: 'capetown.gov.za',
weather: {
temperature: {
celcius: 19,
fahrenheit: 66,
},
windSpeed: {
kph: 27,
mph: 17,
},
humidity: '77%',
},
};
const { weather: { temperature }} = city; 
console.log(temperature);
// Output: { celcius: 19, fahrenheit: 66 }
Example 6: Deeply nested object data can be easily referenced through destructuring.

Using the above example, we are able to access the deeply nested temperature values by destructuring the weather key in the city object.

Setting Defaults Through Destructuring

Default values (or fallbacks) can be created while destructuring to account for data that is expected, yet missing. Consider the following example:

const city = {
name: 'Cape Town',
population: 987007,
website: 'capetown.gov.za',
};
const {
name,
population,
website = 'No Website Available',
country = 'South Africa',
} = city;
const cityWithCountry = `${name}, ${country}`;
console.log(website, cityWithCountry);
// Output: "capetown.gov.za"
// "Cape Town, South Africa"
Example 7: Default values can be set as fallbacks to account for data that may be missing from your data set.

In our example above, the cityAndCountry reference expected a country variable, but one was not provided in our city data set. As a result, the default we set in our destructuring comes into effect, and the reference to country points to the default South Africa.

Defaults assigned through destructuring are always ignored if a value exists in the object being destructured.

To further illustrate this point, a value has been assigned to the website key in the city object. The website reference will point to the object's value (capetown.gov.za) and not the value of the default (No Website Provided), as a value already exists within the object.

Destructuring within Function Signatures

Destructuring is also allowed within function Signatures:

const cityPopulation = ({ name } = {}, website) => {
console.log(`Learn more about ${name} at ${website}`);
};
cityPopulation({ name: 'Cape Town' }, 'capetown.gov.za');
// Output: "Learn more about Cape Town at capetown.gov.za"
Example 8: Destructuring function parameters.

This ensures our functions will always have access to any expected values. The following is an example of a function with defaults being set on destructured parameters:

const cityPop = ({ name = 'Unknown', population=0 } = {}) => {
console.log(`${name} has a population of ${population}`);
};
cityPop({ name: 'Cape Town', population: 987007 });
// Output: "Cape Town has a population of 987007"
cityPop();
// Output: "Unknown has a population of 0."
Example 9: Setting defaults within a function signature.

You may have noticed the destructured parameters are being assigned to an empty object with ={}. This is done to ensure our function calls, without arguments, do not fail with an Uncaught TypeError as demonstrated in the following example:

const cityPop = ({ name = 'Unknown', population=0 } = {}) => {
console.log(`${name} has a population of ${population}`);
};
cityPop({ name: 'Cape Town', population: 987007 });
// Output: "Cape Town has a population of 987007"
cityPop();
// Output: -> Uncaught TypeError: Cannot match against 'undefined' or 'null'.
Example 10: Destructured parameters fail to fallback to defaults when not assigned to an empty object.

Thanks for reading. If you liked this article please consider supporting future installations of this series by recommending it. 👏

Interested in learning more? Click here to view previous parts of this series.

Hacker Noon is how hackers start their afternoons. We’re a part of the @AMI family. We are now accepting submissions and happy to discuss advertising & sponsorship opportunities.
If you enjoyed this story, we recommend reading our latest tech stories and trending tech stories. Until next time, don’t take the realities of the world for granted!

More by Andrew Hill

Topics of interest

More Related Stories