Object Destructuring and Spread Operator in JavaScript

Photo by Jehyun Sung on Unsplash

Object Destructuring and Spread Operator in JavaScript

Out of all the new features in ES6, Destructuring is one of my favorites. Destructuring is very useful and will save you tons on time. Destructuring can be used on arrays but I believe it makes the most sense when used with objects. In this post, we'll discuss about what is destructuring and how it can used with objects. I'll also talk about the spread operator and how it works together with destructuring.

What is Destructuring?

Destructuring is a way to extract or retrieve multiple values from an array or an object. Consider the following snippet

const fruits = ["Apples", "Oranges", "Grapes", "Mangoes"]
const fruitOne = fruits[0]
const fruitTwo = fruits[1]
console.log(fruitOne)
console.log(fruitTwo)

output

"Apples"
"Oranges"

The above code consists of an array called fruits. We are using variables fruitOne and fruitTwo to retrieve the first two fruits from the array using indexes starting from 0. This is how we used to do it before . Now lets see how destructuring makes this easy.

const fruits = ["Apples", "Oranges", "Grapes", "Mangoes"]
const [fruitOne, fruitTwo] = fruits
console.log(fruitOne)
console.log(fruitTwo)
"Apples"
"Oranges"

Our goal is to get the first two values from the fruits array, we put our variable names inside square brackets and initialized it to the fruits array.

How it works?

The idea behind destructuring is that we take the element that we want to destructure and put it on the right hand side of the=essentially we are saying that we are taking apart or extracting values from this structure. Since we are destructuring an array, on the left hand side, we use array brackets or square brackets[] and inside those brackets, we put in the number of variables that suggests the number of values that we want to retrieve from the array. The position of these variables in the square brackets maps to the position of the values in the array. This means that the first variable will store the first value from the array, the second variable will store the second value and so on.

Object Destructing

As mentioned before, destructuring makes the most sense when used with objects. Consider the following code.

let personOne = {
name:"Jack",
age:21,
address:{
state:"California",
city:"Los Angeles"}
};
let name = personOne.name
let age = personOne.age
console.log(name)
console.log(age)

Output

"Jack"
 21

This is how we usually extract values from objects. Now let's see how destructuring helps here.

let personOne = {
name:"Jack",
age:21,
address:{
state:"California",
city:"Los Angeles"}
};
let{name,age} = personOne
console.log(name)
console.log(age)

Output

"Jack"
21

This gives the exact same output as the previous code but as you can see its much easier to write this way instead of using . operator. All we did was replace the square brackets used in array destructuring with {} curly braces. The best part about object destructuring is that it also makes it a lot easier to retrieve values from nested objects. In our example we have a nested object called address. lets see how we can destructure it.

let personOne = {
name:"Jack",
age:21,
address:{
state:"California",
city:"Los Angeles"}
};
let{name,age, address:{state}} = personOne
console.log(name)
console.log(age)
console.log(state)

Output

"Jack"
 21
"California"

All we did was put in the key of the object i.e. address inside the curly braces and since address itself is an object, we added a : and used the same object destructuring syntax again.

The main difference between array destructuring and object destructuring is that, in object destructuring by default you cannot use a variable name of your choice. By default the variable name must same as the key of the value that you want to retrieve from the object. In our example we have used name and age which match the keys in our object.

However with one extra step it is possible to use custom variable names. Take a look at the following syntax.

let personOne = {
name :"Jack",
age : 21,
address : {
state : "California",
city : "Los Angeles"}
};
let{name :firstName, age, address:{state}} = personOne
console.log(firstName)
console.log(age)
console.log(state)

Output

"Jack"
 21
"California"

The above code prints the same output as before but notice how we are using firstName instead of name to print the value of the name. All we did was take the key of the value we want to retrieve from the object use a colon : after the key name and provide custom name that you want to use for that value. Its basically taking the name property and mapping it to the firstName variable that we are using.

Default values

We can use default values while destructuring so that if the value is not present the default value will be used. consider the following example

let personOne = {
name :undefined,
age : 21,
address : {
state : "California",
city : "Los Angeles"}
};
let{name :firstName, age, address:{state}} = personOne
console.log(firstName)
console.log(age)
console.log(state)

In the above code notice that the name of the personOne is set to undefined But what if we want to have a default value that is available when our keys are undefined, we can easily achieve this by providing default values during destructuring.

let personOne = {
name :undefined,
age : 21,
address : {
state : "California",
city : "Los Angeles"}
};
let{name :firstName = "Mark", age, address:{state}} = personOne
console.log(firstName)
console.log(age)
console.log(state)

Output

"Mark"
 21
"California"

since the name is undefined the above code uses the default value for name which is Mark that we have given while destucturing.

Spread operator

Spread ... is an operator that is used to spread out the values of any iterable element like strings, arrays and objects for example:

let address = {
  city : "Los Angeles",
  state : "California"
}
let personOne = {
  name:"Pratik",
  age:22,
  ...address
}
console.log(personOne)

Output


{
  age: 22,
  city: "Los Angeles",
  name: "Pratik",
  state: "California"
}

Spread operator essentially allowed us to bring all the values from the address object into personOne object. This is extremely useful when we want to clone an object or merge two objects.

Cloning an object

let address = {
  city : "Los Angeles",
  state : "California"
}
let personOne = {
  name:"Pratik",
  age:22,
  ...address
}
let personTwo ={
...personOne
}

console.log(personTwo)

Output

{
  age: 22,
  city: "Los Angeles",
  name: "Pratik",
  state: "California"
}

The above example clones personOne into personTwo. So personTwo will have the exact same values as personOne

Merging two objects

let personOne = {
  name:"Pratik",
  age:22,

}
let personTwo ={
    name:"Alex",
    age:29,
    job:"Accountant"

}
let personThree = {...personOne, ...personTwo}

console.log(personThree)

Output

{
  age: 29,
  job: "Accountant",
  name: "Alex"
}

Notice that the output only contains properties from the second object personTwo. Whats actually happening is that when we write let personThree = {...personOne, ...personTwo} we are essentially saying that take whatever is in personOne put it in personThree, then take whatever is inside personTwo and put it in personThree as well but override whatever is already inside personThree, due to this the values of the last copied object overrides any value that is already present. This overriding works only if the keys of both the objects are same. If the objects that are getting merged have completely different keys, the resultant object will have all the values from both the objects.

Wrapping Up.

I hope now you understand destructuring. It's one of my favorite features in ES6 and its also heavily used in frontend frameworks like React. So knowing this will certainly be beneficial.