Web Dev Simplified Blog

How To Use Destructuring And The Spread Operator? (One Of The Best JS Features)

August 24, 2020

JavaScript is constantly evolving with new features being added every year. The biggest set of these changes was when JavaScript ES6 was released. ES6 changed JavaScript completely, and made it a much more modern language with tons of nice features. One of these amazing features, which I use every day, is destructuring and the spread operator. In this article I will show you exactly what both of these are, how you can use them with arrays and objects, and most importantly when to use these features.

If you prefer to learn visually, check out the video version of this article.

What Is Destructuring?

In simple terms destructuring is a fancy way in JavaScript to break apart arrays and objects. It generally allows you to get individual pieces of arrays and objects in less code and opens up a multitude of possibilities. This doesn’t really sound like much more than syntactical sugar, but this small change actually makes doing many tasks significantly easier. Destructuring in arrays and objects is very similar, but it is slightly easier to understand with arrays so I will start by explaining how to destructure arrays.

Destructuring An Array

Imagine you want to get the first element out of an array. Normally you would do this by accessing the element at index 0.

const array = ["A", "B", "C", "D", "E"]
const first = array[0]

console.log(first)
// A

This is pretty straightforward, but what if you now want the first two elements? You will need to write another line of code to get that element.

const array = ["A", "B", "C", "D", "E"]
const first = array[0]
const second = array[1]

console.log(first)
// A
console.log(second)
// B

Again this is not really a big deal, but this can be slightly simplified with destructuring. Instead of getting each element we want individually we will get all elements at once.

const array = ["A", "B", "C", "D", "E"]
const [first, second] = array

console.log(first)
// A
console.log(second)
// B

This syntax probably looks really confusing, but it is actually quite a bit simpler than it looks. Essentially to denote we are doing array destructuring and trying to get elements from an array, we need to wrap our variables inside brackets. This is what we do when we wrap first and second in brackets. Then we just set that group of bracketed variables ([first, second]) equal to the array we want to get the elements from.

This tells JavaScript to take the array on the right side of the equals sign and assign the first element to the first variable in the brackets on the left side of the equals sign. It does the same thing with the second element in the array and assigns it to the second variable in the brackets. This would then continue on until there were no more elements left in the brackets. If we wanted to get the first three elements of the array it is as simple as adding a new variable to the brackets.

const array = ["A", "B", "C", "D", "E"]
const [first, second, third] = array

console.log(first)
// A
console.log(second)
// B
console.log(third)
// C

Also, if you want to skip an element, for example if you only want elements one and three, you would just leave out the name for the second variable, but keep the comma. This comma tells JS to just skip the second element.

const array = ["A", "B", "C", "D", "E"]
const [first, , third] = array

console.log(first)
// A
console.log(third)
// C

Now this on its own is really not that useful since you don’t often need to access an array like this, but what if you want all elements in an array except the first two? This is where the spread operator comes in.

Spread Operator With Arrays

The spread operator is a tool that lets you spread out all the elements of an array or object. This can be used to create new objects or arrays that are clones, but for our specific use case we can combine this with destructuring to get all other elements not specifically destructured already.

const array = ["A", "B", "C", "D", "E"]
const [first, second, ...rest] = array

console.log(first)
// A
console.log(second)
// B
console.log(rest)
// ['C', 'D', 'E']

This is incredibly useful for getting a new array with only some of the elements removed.

We can also use the spread operator to combine multiple arrays together.

const array1 = [1, 2, 3]
const array2 = [4, 5, 6]
const newArray = [...array1, ...array2]

console.log(newArray)
// [1, 2, 3, 4, 5, 6]

Here we are not doing any destructuring and instead are just taking the two arrays and spreading every single value from them into a new array. Since we spread array1 first it will be all the elements at the beginning of the array. We can even combine this with adding individual elements in as well.

const array1 = [1, 2, 3]
const array2 = [4, 5, 6]
const newArray = [0, ...array1, 3.5, ...array2, 7]

console.log(newArray)
// [0, 1, 2, 3, 3.5, 4, 5, 6, 7]

When To Use Destructuring/Spread Operator With Arrays

It may seem like these cases above are contrived and this would never be a useful feature, so here are three ways I use this feature every day.

Copying An Array

If I need to ever create a clone of an array then I can easily spread the array into a new array and now I will have two separate arrays that I can modify without modifying independently.

const array = [1, 2, 3]
const arrayClone = [...array]
arrayClone.push(4)

console.log(array)
// [1, 2, 3]
console.log(arrayClone)
// [1, 2, 3, 4]

Converting An Array-Like Object To An Array

Many times when dealing with JavaScript you get an array-like structure, such as when using document.querySelector, and you cannot use array methods like map on it. To fix this you can just spread the array-like structure into a new array and use all the array methods you want.

const elements = document.querySelector('div')
const array = [...elements]

array.map(a => /* This works */)
elements.map(e => /* This throws an error */)

Destructuring Function Returns

If you have ever worked with React you are very familiar with this one. Destructuring arrays can be used when you want to return multiple values from a function as an array and easily access them.

function sumAndMultiply(a, b) {
  return [a + b, a * b]
}

const [sum, product] = sumAndMultiply(2, 3)

console.log(sum)
// 5
console.log(product)
// 6

Destructuring Objects

Now that is a lot of talk about arrays so let’s now talk about destructuring objects which is the most useful form of destructuring.

Similar to arrays, destructuring an object for specific properties is as easy as wrapping the variables inside of curly brackets to denote we are doing object destructuring. You then just put the object you want to get the values from on the right side of the equals sign.

const person = { name: "Kyle", age: 25 }
const { name, age } = person

console.log(name)
// Kyle
console.log(age)
// 25

As long as you use the same variable name in your destructured variables as is in the object it will work perfectly. Luckily, you can also easily rename variables as well. If you wanted the name variable to be called firstName instead you can do the following.

const person = { name: "Kyle", age: 25 }
const { name: firstName, age } = person

console.log(firstName)
// Kyle
console.log(age)
// 25

This is essentially saying that you are mapping the property name from the object person to a new variable called firstName.

Spread Operator With Objects

Just like with arrays you can spread out the rest of an object while destructuring.

const person = { name: "Kyle", age: 25, favoriteFood: "Rice" }
const { name, ...rest } = person

console.log(name)
// Kyle
console.log(rest)
// { age: 25, favoriteFood: 'Rice' }

As you can see all of the properties that are not destructured are added to a new object. This is really useful for cloning an object without certain properties.

Also, like arrays you can combine together two objects with the spread operator to create a new object. This will also overwrite any values that are in both objects by the one that is defined last.

const person1 = { name: "Kyle", age: 25 }
const person2 = { age: 32, favoriteFood: "Rice" }
const newPerson = { ...person1, ...person2 }

console.log(newPerson)
// { name: 'Kyle', age: 32, favoriteFood: 'Rice' }

Nested Object Destructuring

It is pretty common to have an objected nested inside another object and want to get a specific value from it. With destructuring this is incredibly easy.

const person = {
  name: "Kyle",
  age: 25,
  address: {
    city: "Somewhere",
    state: "One Of Them",
  },
}
const {
  name,
  address: { city },
} = person

console.log(name)
// Kyle
console.log(city)
// Somewhere

The way this works is by saying we are mapping the address property to a specific variable, but instead of actually creating a variable to map that element to we are destructuring that element into the variable city. We are essentially combining the below two lines together.

const { name, address: addressVariable } = person
const { city } = addressVariable

We can even nest array destructuring together, but that is not something you will often need to do.

Default Values

It is pretty common to destructure an object without knowing if a property exists or not. Many times when this is the case there is a default value you want to apply in case that value does not exist.

const person = { name: "Kyle", age: 25 }
const { name = "Sally", favoriteFood = "Banana" } = person

console.log(name)
// Kyle
console.log(favoriteFood)
// Banana

As you can see since the favoriteFood property does not exist in the person object it falls back to the default value. The name property does exist, though, so instead of using the default it pulls the actual value from the person object.

When To Use Destructuring/Spread Operator With Objects

Again it may seem like these cases above are contrived and this would never be a useful feature, but in reality I use this feature every day.

Copying An Object

Just like arrays it is very easy to copy an object and create an exact clone with destructuring.

const person = { name: "Kyle", age: 25 }
const personClone = { ...person }
personClone.name = "Sally"

console.log(person)
// { name: 'Kyle', age: 25 }
console.log(personClone)
// { name: 'Sally', age: 25 }

Destructuring Function Returns

Again just like arrays I use this all the time to return multiple values from a function.

function sumAndMultiply(a, b) {
  return { sum: a + b, product: a * b }
}

const { sum, product } = sumAndMultiply(2, 3)

console.log(sum)
// 5
console.log(product)
// 6

Destructuring Function Parameters

In JavaScript it is very common to pass an object to a function so having the ability to destructure the object in the function definition and define defaults is incredibly useful.

function printPerson({ name, age, favoriteFood = "None" }) {
  console.log(`Name: ${name}. Age: ${age}. Food: ${favoriteFood}.`)
}

const person = { name: "Kyle", age: 25 }

printPerson(person)
// Name: Kyle. Age: 25. Food: None.

Conclusion

We covered a ton in this article. It ended up being much longer than I anticipated, but that is because destructuring and the spread operator are useful in so many situations. Next time you are programming make sure to think about how you could use this operator to improve the quality and maintainability of your code.