Object destructuring in Javascript
Tags: javascript, es6, destructuring, patterns
Published: 2021-01-24 18:06:14

In this article, **you are going to learn all about object destructuring** in Javascript. Previously we learned about [Array destructuring in Javascript](https://codelistic.com/array-destructuring-in-javascript), so now let’s see how to destructure objects following pretty much the same syntax.

You’re also going to learn some cool tricks you can do using object destructuring like **optional function arguments**.

Object destructuring is a bit more complicated than array destructuring, but **keep reading to the end** and you’ll become a Javascript destructuring ninja in no-time!! 😄

## Basics
When declaring an object, for example:

```jsx
const employee = {
	firstName: 'Bruce',
	lastName: 'Lee',
	role: 'Teacher',
};
```

We can say we packed the key-value pairs of data which we can retrieve at any point later by using the so-called “dot-syntax” and store the values of specific keys into variables, e.g.:

```jsx
const firstName = employee.firstName;
const lastName = employee.lastName;
const role = employee.role;
```

We immediately see that this can get quite repetitive	as the number of values we want to retrieve gets larger. Instead, we can utilize **object destructuring** to unpack the data we want and avoid repeating ourselves:

```jsx
const { firstName, lastName, role } = employee;

console.log(firstName); // Bruce
console.log(lastName); // Lee
console.log(role); // Teacher
```

Unlike array destructuring, we should be more careful if we want to destructure into variables that have been declared before, so for example:

```jsx
let firstName;
let lastName;
let role;

{ firstName, lastName, role } = employee; // Syntax Error !!
```

This will result in an **error**, since using curly braces outside of the context of declaring the variables ( `let`), Javascript considers them to represent a code block instead. So, we should remember to explicitly wrap the whole expression using parenthesis  `( … )` like this:

```jsx
( { firstName, lastName, role } = employee )

console.log(firstName); // Bruce
// ... etc
```

Notice how we **needed to remove the semicolon** `;` after the `employee` keyword in this case.

### Missing elements

If we try to destructure an element which doesn’t exist in the object, the variable gets assigned the value of `undefined`:

```jsx
const employee = {
	firstName: 'Bruce',
	lastName: 'Lee',
	role: 'Teacher',
};

let { firstName, middleName } = employee;
console.log(firstName); // Bruce
console.log(middleName); // undefined
```

You can also notice that we omitted to destructure some of the keys that exist in the `employee` variable (`lastName` and `role`). Using object destructuring we have the liberty of choosing what we need to extract and safely ignoring the rest.

### Changing the order

Changing the order of variables we are destructuring into doesn’t affect the destructuring in any way:

```jsx
let { role, lastName, firstName } = employee;
console.log(role); // Teacher
// ...
```

This is possible because in JS objects store their value by named keys, unlike arrays by index where the order matters.

### Renaming

But what if we want to use a **different name for the variables** we destructure the object into? 
A typical scenario for this is when you fetch data via an API call from the backend that might have a different naming convention for variables, or a different variable name just fits better into the current context.

Let’s check the following example:

```jsx
const employee = {
	first_name: 'Bruce',
	last_name: 'Lee',
	role: 'Teacher',
};

let { 
	first_name: firstName, // rename
	last_name: lastName, // rename
	role
} = employee;

console.log(firstName); // Bruce
console.log(lastName); // Lee
console.log(role); // Teacher
```

As you can see, we can use the colon `:` operator to rename the variable we are extracting the data into.
An easy way to remember this is to imagine saying to yourself 

 `this: into that`

### Default values

We’ve seen previously that if we try to destructure a value for a key in the object that doesn’t exist, we get `undefined`:

```jsx
const employee = {
	firstName: 'Bruce',
	lastName: 'Lee',
};

let { firstName, middleName } = employee;
console.log(middleName); // undefined
```

We can actually define a **default value** which will be assigned instead of `undefined`:

```jsx
let { firstName, middleName = 'The Dragon' } = employee;
console.log(middleName); // The Dragon
```

This technique is very useful for defining **functions with optional arguments**, as we are going to learn later.

It’s also possible to use both renaming and default values together for greater flexibility:

```jsx
const employee = {
	first_name: 'Bruce',
	last_name: 'Lee',
	role: 'Teacher',
};

// ...

let {
	first_name: firstName,
	middle_name: middleName = 'The Dragon',
} = employee;
console.log(firstName); // Bruce
console.log(middleName); // The Dragon
```

### Dynamic object destructuring

Don’t get frightened by the title, it’s a mouthful, but actually, it boils down to this question:

How do we destructure an object property for which we don’t know the key name in advance? 

In other words, the key name will be determined during runtime stored in a variable. Let’s see an example:

```jsx
// the variable key can be set anywhere in the program
// i.e. stored as a function return value, etc.
let key = 'role';

const employee = {
	first_name: 'Bruce',
	last_name: 'Lee',
	role: 'Teacher',
};

let {[key]: val} = employee;
console.log(val); // Teacher
```
 
We can see that we used the variable `[key]`. The square brackets mean that  _the value_ stored in the variable `key` should be used as a key when destructuring, which happens to be `'role'` in our case.  The `[key]` is called [computed property name](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#computed_property_names) and can also be used when declaring objects.

### Nested object destructuring

We can destructure complex nested objects which can contain arrays as well. In that case we can combine both object and array destructuring (see [Array destructuring in Javascript](https://codelistic.com/array-destructuring-in-javascript)) at the same time:

```jsx
const employee = {
	firstName: 'Bruce',
	lastName: 'Lee',
	role: 'Teacher',
	addresses: [
		{
			street: 'Main street 9',
			city: 'San Francisco',
			country: 'USA',
		},
		{
			street: 'Not main street 122',
			city: 'Hong Kong',
			country: 'China',
		},
	],
};

let {
	lastName,
	role: occupation,
	addresses: [
		{city: recentCity}, {city: oldCity}
	]
} = employee;

console.log(lastName); // Lee
console.log(occupation); // Teacher
console.log(recentCity); // San Francisco
console.log(oldCity); // Hong Kong
```

We can see that we managed to “dig out” cities from the nested structure of the employee object by writing the destructuring pattern that matches that object. In this case, we only needed cities from `addresses` objects so other values were ignored. 

## Tricks using object destructuring
Now that we learned the basics of object destructuring, let’s dive into some of the tricks we can perform using it.

### Save the remaining properties as a new object

Let’s say we destructure only some of the properties of an object, but we want to store the rest (unprocessed properties) into a new object variable.
We can do this similarly to array destructuring using the spread `...` operator.

```jsx
const userProfile = { 
	firstName: 'John', 
	lastName: 'Deere', 
	socialSecurityNo: 123
}; 

const { socialSecurityNo, ...rest } = userProfile; console.log(rest); // { firstName: 'John', lastName: 'Deere' }
```

Keep in mind that `…rest` has to always be located at the end of destructuring, which means something like `const { firstName, …rest, socialSecurityNo } = userProfile` would throw an error.

### Destructuring of function arguments

So far, we’ve been destructuring objects using the assignment `=` operator. But the destructuring syntax can also be used in the function definition, where we can define **how an object is going to be destructured once we pass it to a function call as an argument**.

```jsx
const employee = {
	firstName: 'Bruce',
	lastName: 'Lee',
	role: 'Teacher',
	address: {
		street: 'Main street 9',
		city: 'San Francisco',
		country: 'USA',
	},
};

function processEmployee({ firstName, address: { city } }) {
	console.log(firstName);
	console.log(city);
}

// Now we call the function
processEmployee(employee);
// the function call prints the following:
// Bruce
// San Francisco
```

This is great because it means we don’t have to unpack the function input argument using the dot syntax in which case the function would look like this:

```jsx
function processEmployee(employee) {
	const firstName = employee.firstName;
	const city = employee.address.city;
	console.log(firstName);
	console.log(city);
}
```

**Yuck!** As you can see, this ends up with more lines of code and ugly repetition when using the dot syntax. This issue gets increasingly annoying as we need more object properties.

But where object destructuring really shines is when we want to define a function with optional arguments.

### Optional function arguments with default values

Let’s assume we have defined the following function for showing some information related to a project, it’s category and tasks associated to it:

```jsx
function showProjectInfo(projectName, category, tasks) {
	console.log(projectName);
	console.log(category);
	for (const task of tasks) {
		console.log(task);
	}
}

showProjectInfo(
	'Array Destructuring', 
	'Blog', 
	['Write outline', 'Write article', 'Publish article']
);
/* Output shown: */
// Array Destructuring
// Blog
// Write outline
// Write article
// Publish article
```

And now let’s say that we want to make **some of the arguments of this function optional**, so for example we want this function to be able to only take in `tasks`. If we don’t provide arguments `projectName` and `category` in the function call, we want to set the values of these arguments to `Unknown` and `Uncategorized`, respectively.

The first approach you might take is to use the regular default arguments syntax provided by Javascript:

```jsx
function showProjectInfo(projectName='Unknown', category='Uncategorized', tasks) {
	// ...
}
```

There are **a couple of issues with this approach** when calling this function:

1. We need to know how many arguments this function takes
2. We need to know what’s the order of arguments to pass in
3. We cannot leave out a certain argument from the call

So if we wanted to call it by providing only `tasks` and leaving the `projectName` and `category`  to have the default values set, we would have to explicitly call the function with values for those arguments being  `undefined`:

```jsx
	showProjectInfo(undefined, undefined, ['Write outline', 'Write article', 'Publish article']);
/* Output shown: */
// Unknown
// Uncategorized
// Write outline
// Write article
// Publish article
```

Otherwise, if we called it using `showProjectInfo(['Write outline', 'Write article', 'Publish article']);` we **would get an error**.

Fortunately, we can utilise the power of **object destructuring with default values** to solve this issue:

```jsx
function showProjectInfo({
	projectName: name = 'Unknown', // rename + default value
	category = 'Uncategorized', // default value
	tasks,
}) {
	console.log(name); // `projectName` was renamed to `name` 
	console.log(category);
	for (const task of tasks) {
		console.log(task);
	}
}
```

Now we can call this function by passing in an object with only the `tasks` key set to the array of tasks:

```jsx
showProjectInfo({ tasks: ['Write outline', 'Write article', 'Publish article'] });
/* Output shown: */
// Unknown
// Uncategorized
// Write outline
// Write article
// Publish article
```

Notice that we left out `projectName` and `category` from the call completely and the **default values were assigned in the function**. We can choose to set the category as well and leave out only `projectName` . Additionally, **we don’t even have to think about the order of these parameters** during the function call:

```jsx
showProjectInfo({
	tasks: ['Write outline', 'Write article', 'Publish article'],
	category: 'Blog',
});
/* Output shown: */
// Unknown
// Blog
// Write outline
// Write article
// Publish article
```

We can even choose to destructure the array `tasks` provided as a function argument using **array destructuring**, for example let’s say we only wanted to capture maximum 2 first tasks:

```jsx
function showProjectInfo({
	projectName: name = 'Unknown',
	category = 'Uncategorized',
	tasks: [task1, task2], // first two tasks
}) {
	console.log(name);
	console.log(category);
	console.log(task1);
	console.log(task2);
}
```

Now if we call the function with e.g. 3 tasks we see we get only first 2 shown:

```jsx
showProjectInfo({ 
	tasks: ['Write outline', 'Write article', 'Publish article'] 
});
// Unknown
// Uncategorized
// Write outline
// Write article
```

Let’s now define the same function as before, but make all arguments optional by also specifying the `tasks` array to have the default value of `[]` (an empty array):

```jsx
function showProjectInfo({
	projectName: name = 'Unknown',
	category = 'Uncategorized',
	tasks = [],
}) {
	console.log(name);
	console.log(category);
	for (const task of tasks) {
		console.log(task);
	}
}
```



```jsx
showProjectInfo({});
// Unknown
// Uncategorized
```

But, notice that we still **need to remember to provide an empty object** to the function call in this case. If we want to remove this requirement and be able to perform the call like `showProjectInfo()` , we can use a trick, which is to **add an empty object as a default value** for the whole object we pass in:

```jsx
function showProjectInfo({
	projectName: name = 'Unknown',
	category = 'Uncategorized',
	tasks: [task1, task2] = [],
} = {}) { // We added "= {}" here !!
	/// ...
}
```

Now we can call the function without providing any arguments, which makes the default value of `{}` take effect and is the same as calling the function using it:

```jsx
showProjectInfo();
// Unknown
// Uncategorized

showProjectInfo({});
// Unknown
// Uncategorized
```

## Conclusion
That’s it! You’re now a Javascript destructuring ninja! 
Now go ahead and be [DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) !!!.

If you need a refresher on the **array destructuring** in Javascript, take a look at my previous article on the topic [here](https://codelistic.com/array-destructuring-in-javascript).