Some use cases of object destructuring

Destructuring is a cool feature, which makes our code easier to write and read. In this post I will briefly describe what object destructuring is and will mention two frequent use cases.

Destructuring introduced in ES6 (ES2015) is a nice way of extracting values and properties from arrays and objects and, at the same time, saving them into variables.

How does it work?

Object destructuring is a cool way of replacing the dot notation when referring to the properties of objects. Assume we have the following very simple object:

const book = {
  title: 'Harry Potter and the Philosopher\'s Stone',
  author: 'J. K. Rowling',
  review() {
    return 'A great book!';
  }
};

In the pre-ES6 era we needed to access the title property like this:

const title = book.title;
console.log(title); // Harry Potter and the Philosopher\'s Stone

With destructuring, we can write the following syntax:

const { title } = book;
console.log(title); // Harry Potter and the Philosopher\'s Stone

The { title } notation indicates that we are extracting a property of an object (curly braces). title is the name of the property in book we want to pull out and we save it into the variable called title.

So far the code is not much shorter but we can use the same const declaration to extract other properties from the same object:

const { title, review } = book;
console.log(title); // Harry Potter and the Philosopher's Stone
console.log(review()); // A great book!

We could now save a line of code and the shorter the code is, the better.

It’s also possible to give another, more expressive name to the extracted variables:

const {
  title: bookTitle,
  review: bookReview
} = book;
console.log(bookTitle); // Harry Potter and the Philosopher's Stone
console.log(bookReview()); // A great book!

In this case we save the title and review properties of book into the bookTitle and bookReview variables, respectively. The title and review variables won’t be available anymore (because they are not declared) and trying to accessing them will throw a ReferenceError.

Use cases

Now let’s have a look at some cool use cases of object destructuring.

Requiring methods

This is my all-time favourite. We very often need to require modules at the top of the files in Node.js. Every time we need a method from a module (and not the whole module itself), we can use destructuring.

The expect method of the popular test assertion library, Chai is a great example:

const { expect } = require('chai');

Here we pull out the expect method and save it into a variable of the same name. Nothing can stop us now from writing a cool assertion:

expect(author).to.equal('J. K. Rowling');

We can also use destructuring when we import our custom modules. Say that we have a file called maths.js and export several methods:

module.exports.sum = (a, b) => a + b;

module.exports.product = (a, b) => a * b;

module.exports.power = (a, b) => a ** b;

module.exports is an object and we are adding three methods to it, sum, product and power. As such, we can use destructuring when requiring them in another file:

const { product, power } = require('./maths');

console.log(product(3, 5)); // 15
console.log(power(2, 4)); // 16

Cool!

Use of destructuring in array methods

JavaScript’s map and filter methods can be applied on arrays and we can use destructuring to make our code a bit cleaner when using these methods too.

Assume we have a books object with the following properties:

const books = [
  {
    title: 'Harry Potter and the Philosopher\'s Stone',
    author: 'J. K. Rowling',
    year: 1997,
    reviews: {
      excellent: 3,
      good: 5,
      fair: 2
    }
  },
  {
    title: 'The Lord of the Rings',
    author: 'J. R. R. Tolkien',
    year: 1954,
    reviews: {
      excellent: 6,
      good: 3,
      fair: 1
    }
  },
  {
    title: 'The Girl on the Train',
    author: 'Paula Hawkins',
    year: 2015,
    reviews: {
      excellent: 2,
      good: 4,
      fair: 2
    }
  },
  {
    title: 'The Bourne Identity',
    author: 'Robert Ludlum',
    year: 1980,
    reviews: {
      excellent: 6,
      good: 1,
      fair: 2
    }
  }
];

No surprise here, Harry Potter is still alive and rules.

Because we love reading we can map over the books and create a custom review message by adding the “… is great!” string to the title of each book.

Without destructuring we have to do something like this:

const booksRead = books.map((book) => {
  return `${ book.title } by ${ book.author } is great!`;
});

Logging booksRead to the console will return the following:

[ 'Harry Potter and the Philosopher\'s Stone by J. K. Rowling is great!',
  'The Lord of the Rings by J. R. R. Tolkien is great!',
  'The Girl on the Train by Paula Hawkins is great!',
  'The Bourne Identity by Robert Ludlum is great!' ]

As we can see map accepts a function whose first (and in this case, the only) argument is the current book object in the iteration. Because it’s an object and we will work with its properties in the return statement, we can apply destructuring.

Let’s pull out the title and author properties from books:

const booksRead = books.map(({ title, author }) => {
  return `${ title } from ${ author } is great!`;
});

{ title, author } indicates that we are extracting the title and author properties from an object (curly braces) and saving them into the variables title and author, respectively.

Getting one level deeper

OK, this is all good but so far it has only been rather nice then convincing.

Let’s have a look at books, which also contains a nested object. Can we use destructuring to obtain properties from reviews?

Yes, we can and the real power of destructuring will show off here.

Our task is to select the books which received an excellent rating from more than five readers and return the “… is excellent!” text along with the title and author of the excellent books. To achieve this we first filter the books object and return the books that meet the requirement of being voted excellent by more than five people. Then we map over the already filtered array and insert the title and author into our message.

It looks like this without destructuring:

const excellentBooks = books
  .filter((book) => {
    return book.reviews.excellent > 5;
  }).map((excellentBook) => {
    return `${ excellentBook.title } by ${ excellentBook.author } is excellent!`
  });

This returns

[ 'The Lord of the Rings by J. R. R. Tolkien is excellent!',
  'The Bourne Identity by Robert Ludlum is excellent!' ]

Indeed, these books are excellent.

However, it’s quite inconvenient to use the dot notation for the nested reviews object to get the excellent property.

On the other hand, in the chained map method we only receive the books that are already rated excellent (we receive it as the returned value from filter), so the naming of the current book object should reflect this (excellentBook).

It would be very easy to get lost if we attached another method like sort to order them by year, for example. I reckon with the map part attached the code is already not easy to read.

We can make our code cleaner with destructuring:

const excellentBooks = books
  .filter(({ reviews: { excellent } }) => {
    return excellent > 5;
  }).map(({ title, author }) => {
    return `${ title } by ${ author } is excellent!`
  });

In the filter method we only use the excellent property of books. Watch how the nested object is shown in the argument of map. { reviews: { excellent } } indicates that we extract the reviews property first, which is also an object, and then we will pull out the excellent property from it.

The map part is also easy to read and we don’t have to bother with the naming here. We know that the properties derive from books and we just pull put the ones we need (title and author) to work with.

Conclusion

Object destructuring is a really cool feature and it has been with us for a while. It makes our code cleaner and more readable. It might take a while for one to get used to it but it’s worth the effort because I’m sure the code will be cleaner and the developer will be happier.

Thanks for reading and see you next time.