How to easily access nested object data

Let's say we're going to start working with user data in our applications. And aside from just having a user's name like before, we have to manage a lot more information about them, like their username, email and job title.

So to be able to conveniently organize all of this basic, that is primitive JS data, expressed as strings, we use a better data structure that was created for better organizing and keeping track of sets of static data, namely objects. So here we have our first user, with all of the data expressed as an object:

const user = {
  name: "Reed",
  username: "ReedBarger",
  email: "reed@gmail.com",
  details: {
    title: "Programmer",
  },
};

And say we are making for each user a profile page to show some information about them. So let's say we have a function that does just that called displayUser:

function displayUser() {}

And this function takes the user data from the outer scope and using it, we want to display the user's username and their email address. For now, we'll just log it to the console:

function displayUser() {
  console.log("Username: username, Email: email");
}

So now we want to replace username and email with the actual values from 'user'.

So if you've worked with functions before, you know that we can use dot notation to be able to get whatever properties that we want off of an object, so using template literals, we can interpolate first the name from user.username and title from user.email:

function displayUser() {
  console.log(`Username: ${user.username}, Email: ${user.email}`);
}

Simple enough. But say if we wanted to include more information from the user, more properties. Notice how many times we would have to repeat the object reference user. It gets annoying to have to do that, to have to repeat ourselves. As we mentioned earlier, we want to avoid that as much as we can within our programming.

So what's a better approach. Well what if instead of having to reference the user object every time we wanted a property off of it, we just reference the property. So that it looked like this:

function displayUser() {
  console.log(`Username: ${username}, Email: ${email}`);
}

A lot more convenient and readable this way, right? So now these values are detached from the user object itself and they are functioning like variables that we declared on our own. Can we do this, can we make this work?

Object destructuring

In fact, we can, using a feature called destructuring. And this enables us to pluck off the properties that we want from our object, to destructure them from the object, and make them their own variables.

The way that we do that is by taking the user object and looking at our code, since we want to make the properties username and email variables now, we can set user equal those two variables:

const username, email = user;

But written like this, our code won't work. We need to tell JS that we are trying to get properties from an object and put them into variables of the same name.

To do that, we just have to wrap these two variable declarations in a set of curly braces, just like this:

const { username, email } = user;

And if we were to run our function:

displayUser();

[Run code] We see that this code works!

So object destructuring allows us to pull whatever properties out of objects that we like and conveniently make them variables, which as you can see, makes our code a lot more readable and concise. Destructuring lets us grab only the stuff we need, without having to use the whole object each time.

Let's take another example. Say we want to create a function that displays the user bio, called displayUserBio. Using what we know about destructuring, figure out how to write this function so that it uses the destructured name property and display it in the console...

We'll begin once again by taking our user object and setting it equal to a set of curly braces. This syntax make look weird, kind of like a reverse object. And since we want to turn a property into a new variable (that we don't want to change), we prepend it with const.

const {} = user;

Then we select the property that we want and it's value gets put into a variable of the same name. In our case, name. Note that the provided variable name has to match and existing property on the object. We can't just name it whatever we want.

const { name } = user;

So now we're getting name and can use it in our function:

function displayUserBio() {
  console.log(`${name}`);
}

And it works:

displayUserBio();

[Run code]

So that might have been pretty straightforward, but what about if we want to provide the user's title. For example, name is a ...:

function displayUserBio() {
  console.log(`${name} is a ...`);
}

For the title property, we see that it's included on a nested object, details. So to get access to it with the normal dot notation, we would have to say user.details.title, which is kind of ugly.

How do we use destructuring to make the title property of the nested object a variable as well?

Well there are two ways we could do this:

  1. We could use partial dot notation to get access to details object by saying:
user.details;

And then destructure the title property from it, like so:

const { title } = user.details;

And then use it within our function, like name:

function displayUserBio() {
  console.log(`${name} is a ${title}`);
}

displayUserBio();

[Run code] And when we run this code, it works. But here we have to include two separate destructuring statements for the same object, user.

Is there a way we could condense it into 1?

This brings us to the second approach. To use the statement where we destructured name from user directly, what we can do is first destructure the details property like so, since nested objects are properties of their parent object:

const { name, details } = user;

And then we can destructure another level further by adding after the nested object a colon and another set of curly braces to destructure that object:

const {
  name,
  details: {},
} = user;

And finally, from details, we can turn the title property into a const variable in the same process as 'name':

const {
  name,
  details: { title },
} = user;

So if we comment out the previous solution and run this code:

const {
  name,
  details: { title },
} = user;
// const { title } = user.details;

function displayUserBio() {
  console.log(`${name} is a ${title}`);
}

displayUserBio();

[Run code] It still works.

So this is the power of object destructuring to make our code more concise and convenient. And the benefits don't stop there. We can also apply object destructuring to functions.

For example, say that instead of relying on our object data being in the global scope, we wanted to pass it as a parameter.

So for displayUserBio, comment out our destructuring statement in the scope above:

// const { name, details: { title } } = user;
// const { title } = user.details;

function displayUserBio() {
  console.log(`${name} is a ${title}`);
}

displayUserBio();

Instead, we want the function to be more reusable to other bios and as a result, pass the user data as an argument.

So we'll pass the entire user object to displayUserBio and then call the parameter userData:

function displayUserBio(userData) {
  console.log(`${name} is a ${title}`);
}

displayUserBio(user);

So now we're getting all of the user data directly, but our function is now broken because we're not getting the individual properties name and title.

However what's great about destructuring is that it can be used in a space like the parameters of a function. So since we know that userData is an object with both the name and title properties, we can perform the same exact destructuring operation, but directly in the parameters of the function.

So let's just copy the commented-out destructuring operation and replace it with our userData parameter:

function displayUserBio({ name, details: { title } }) {
  console.log(`${name} is a ${title}`);
}

displayUserBio(user);

[Run code] And once again, our code works exactly as before.

Review

So don't underestimate the power and flexibility of destructuring with objects. They make accessing properties from them incredibly easy and wherever you use objects, whether it's on their own or in the parameters of functions or wherever else, you can leverage destructuring to get and access only the property values you need.