A Simple Guide to Destructuring and ES6 Spread Operator

The evolution of JavaScript to ES6 version has brought a whole array of new tools and utilities. These tools allow us to perform some common operation in a more concise and elegant way. One such new feature is the spread operator. The operator’s shape is three consecutive dots and is written as: ...
.
The Spread Operator has more than one function. In a sense, it is overloaded. It can also be used as rest operator in conjugation with destructuring. In ES6, the spread operator worked only for arrays. However, according to a proposal that has reached Stage 4, you can use the spread operator on objects too.
When a proposal reaches Stage 4, it means that it has been finalised by the TC39 committee and will be available in the next release of ES version. In this case, the next version will be ES2018(ES9). We are going to see both the use cases in this article.
Introduction: Spread Operator
The spread operator allows an iterable to spread or expand individually inside a receiver. Iterables are anything that can be looped over such as strings, arrays, and sets. For example —
const codeburst = 'CODEBURST'; // Line 1
const characters = [ ...codeburst ]; // Line 2// [ 'C', 'O', 'D', 'E', 'B', 'U', 'R', 'S', 'T' ]
In this case, the thing that we are expanding is the string CODEBURST
. In line 2, the three dots act upon the string in the variable codeburst
and spread each individual character inside the receiver. The receiver is the array. If you omit the receiver, you will get an error.
Here’s another example —
const items = ['This', 'is', 'a', 'sentence'];console.log(items) // Line 1
console.log(...items) // Line 2// [ 'This', 'is', 'a', 'sentence' ] // Output 1
// This is a sentence // Output 2
Here we have an array of strings called items
. First, we just print items
. The output is ['This', 'is', 'a', 'sentence']
. It is same as the items
variable itself. Now, we print ...items
. We get This is a sentence
. Notice that this is not an array anymore. Instead, it is a string. console.log(...items)
behaved as this line: console.log('This', 'is', 'a', 'sentence')
.
The logic is same — Each individual member of the array was plucked from its location and kept inside the receiver. The receiver, in this case, is a function. So the individual items become function arguments.
Another example —
Math.max
takes n number of numeric parameters and returns the largest number in the group.
Math.max(5, 6, 8, 9, 11, 999);// 999
Imagine that we don’t know beforehand how many numbers we are going to test. In the above example, there are six. We may have a hundred next time. If we hardcode the numbers like above, we lose the flexibility of checking maximum of more numbers at runtime.
Since we know from above that we can unpack an iterable inside an appropriate receiver, we may be able to solve the problem like this —
const numbers = [5, 6, 8, 9, 11, 999];Math.max(...numbers)
The same logic applies here as in the previous two examples. Every individual number is plucked from the numbers
array and kept inside the receiver. The receiver, in this case, is max()
function and it receives the individual numbers as arguments.
Here’s an example with objects —
const obj = { name: 'Foo', age: 22 };
const newObj = { ...obj }console.log(newObj)// { name: 'Foo', age: 22 }
Here we are spreading an object obj
. The receiver in this case is another object newObj
. When the thing that is being spread is an object and the receiver is an object too, then the key-value pairs are copied together instead of just values. Mostly, spread operator with objects is used to make a copy of an existing object or to make a new object with more properties. Here’s how you can “combine” two objects.
const obj1 = { firstName: 'Foo', age: 22 };
const obj2 = { lastName: 'Bar', gender: 'M' };const newObj = { ...obj1, ...obj2, planet: 'Earth' };console.log(newObj)// { firstName: 'Foo', age: 22, lastName: 'Bar', gender: 'M', planet: 'Earth' }
Here, the newObj
has the properties of obj1
, obj2
. It also has an extra property planet
.
newObj
is a copy of the obj1
and obj2
. Actually, any enumerable property on objects will be copied to newObj
. The copying process using spread operator is shallow. There are some differences between copying using spread operator and copying using Object.assign
. Advance users may want to refer to this.
Destructuring
Destructuring means taking out ( technically, making a copy of ) individual items from an object or an array and assigning them to a variable. Example ( with arrays) —
const address = [221, 'Baker Street', 'London'];const [ houseNo, , city ] = address;console.log(houseNo, city)// 221 'London'
Notice the bold line. To the left of the =
sign, we declared the variables which will hold the extracted values. We use const
because we intend to make the variables constant. let
could have also been used instead. Then, we wrote the names of the variables in an array-like syntax, that is, beginning and ending with a [
and ]
since we are destructuring from an array.
Notice two consecutive commas in [ houseNo, , city ]
. It may not feel like natural array syntax. It looks like it is missing something in between those two commas. Your intuition is right. We can omit values from being destructured. If a variable name is not specified, the value is not assigned to anything. Here’s a small diagram to help illustrate the idea —

In this case, we need only houseNo
and city
. So we exclude the street name.
Let’s see how to do the same in the objects —
const details = { firstName: 'Code', lastName: 'Burst', age: 22 };const { firstName, age } = details;console.log(firstName, age);// Code 22
Notice the bold line. It uses destructuring to take out the firstName
and age
property from the details
object. Unlike arrays, we need to put a pair of curly braces because we are destructuring from an object. Had it been an array, you would have used a square bracket as in the previous example.
In arrays, we could have specified any variable name for the values to be destructured. However, with an object, the variable name has to match the property name in the object. That’s why in the example we wrote firstName
since details has that property. An unknown property would return undefined
.
const { address } = details;console.log(address)// undefined
Here’s a small illustration to hit the concept home.

It is important to note that destructuring does not remove properties or values from the original object or array. It merely copies it.
Rest Operator
Syntactically, it looks exactly the same as spread operator. But it’s function is the exact opposite of the spread Operator. If Spread operator expands individual items, then rest operator collects a bunch of items and puts them into arrays and objects. Let’s see an example —
const numbers = [1, 2, 3];const [ firstNumber, ...restOfTheNumbers ] = numbers;console.log(firstNumber, restOfTheNumbers);// 1 [ 2, 3 ]
Using destructuring, we extract the firstNumber
. We don’t want individual numbers anymore. So we collect them in the restOfTheNumbers
array.
Notice that restOfTheNumbers
is an array. Since rest operator collects items, it needs to place them in a container. That container is an array when we destructure from an array or strings.
const [ firstLetter, ...restOfTheLetters ] = 'Codeburst';
console.log(firstLetter, restOfTheLetters);// C [ 'o', 'd', 'e', 'b', 'u', 'r', 's', 't' ]
A few other things to note are —
- All concepts of destructuring apply with rest operator since rest operator is nothing more than a specialised form of destructuring.
- It is always to the left side of the
=
whereas the spread operator will be on the right side. - In arrays and objects, the rest operator can only come at the end. That is, this syntax won’t work —
const [ firstLetter, ...restOfTheLetters, lastLetter ] = 'Codeburst';
Let’s see how the rest operator behaves with objects with an example —
const details = {
firstName: 'Code',
lastName: 'Burst',
age: 22
};const { age, ...restOfTheDetails } = details;console.log(age, restOfTheDetails);// 22 { firstName: 'Code', lastName: 'Burst' }
Following the destructuring of age
property, we collect the rest of the properties in restOfTheDetails
. The collection container in this case will be an object, since we are destructuring from an object. All other observations from the previous passages apply here as well.
It’s not over yet. You can do more with these operators that just shown in the above examples. Having understood the basics of Rest/Spread operator and destructuring, you can follow these links for practical use-cases and more in-depth discussions.
- Demos of Destructuring — Lists several demos of how you may destructuring to solve commonly occurring programming problems.
- Mozilla Docs — For Destructuring
- Mozilla Docs — For the Spread Syntax
- ES2018: Rest/Spread Properties — A more in-depth discussion of some pitfalls.
I hope you enjoyed this guest post! This article was written by Arfat Salmon exclusively for CodeBurst.io
✉️ Subscribe to CodeBurst’s once-weekly Email Blast, 🐦 Follow CodeBurst on Twitter, view 🗺️ The 2018 Web Developer Roadmap, and 🕸️ Learn Full Stack Web Development.