Intro
Since the 2015 version of the ECMAScript specification Javascript developers got access to a lot of new functionality regarding working with arrays and objects. In this article, I am going to explain 'spreading', 'destructuring' and the 'rest parameters' by showing you examples of how they can be used to reduce your code length or make it more easily understandable.
These concepts are not common in other programming languages so they can be something completely new for many developers, even ones that have been in the game for a long time.
Spreading
The spread syntax (...
) is a very helpful technique when working with arrays or objects since it allows you to unpack and expand objects or arrays and make shallow copies of them.
Spreading objects
Spreading can be used to copy an object, like Object.assign()
, or update it.
Copy
// without spreading
const originalObject = {
enabled: true,
darkMode: false
}
const secondObject = Object.assign({}, originalObject)
// with spreading
const originalObject = {
enabled: true,
darkMode: false
}
const secondObject = { ...originalObject }
console.log(secondObject)
// Output:
{enabled: true, darkMode: false}
Keep in mind this only creates a shallow copy of the object and nested objects will still be passed by reference.
Update
Updating objects is effortless using spreading, so let's add another property, stayLoggedIn
to our originalObject
.
const originalObject = {
enabled: true,
darkMode: false
}
const updatedObject = {
...originalObject,
stayLoggedIn: true
}
console.log(updatedObject)
// Output:
{enabled: true, darkMode: false, stayLoggedIn: true}
One thing that has to be noted when updating nested objects is that they have to be spread as well, because they will be overwritten if you do not.
const originalObject = {
enabled: true,
settings: {
darkMode: false
}
}
const updatedObject = {
...originalObject,
settings: {
stayLoggedIn: true
}
}
console.log(updatedObject)
// Output:
{enabled: true, settings: {stayLoggedIn: true}}
As said above, the settings
object will be overwritten. To solve this, you need to spread the nested objects like this:
const originalObject = {
enabled: true,
settings: {
darkMode: false
}
}
const updatedObject = {
...originalObject,
settings: {
...originalObject.settings,
stayLoggedIn: true
}
}
console.log(updatedObject)
// Output:
{enabled: true, settings: {darkMode: false, stayLoggedIn: true}}
Spreading arrays
Using the spread syntax, you can simplify quite a lot of common tasks, like duplicating arrays.
Duplicate
const originalArray = ['A', 'B', 'C']
const copyArray = [...originalArray]
originalArray.pop()
console.log(copyArray)
// Output:
['A', 'B', 'C']
Cool, right? This creates a shallow copy of the array, this means that all top level properties will be cloned but nested properties will be passed by reference still. But that's not the end, you can also concatenate arrays way easier now.
. Concat
const first = ['A', 'B', 'C']
const second = ['D', 'E', 'F']
const union = [...first, ...second]
console.log(union)
// Output:
['A', 'B', 'C', 'D', 'E', 'F']
You can also split up a string into an array using spreading like this:
const string = 'awesome'
const charArray = [...string]
console.log(charArray)
// Output:
['a', 'w', 'e', 's', 'o', 'm', 'e']
Destructuring
Destructuring is very helpful because it lets you assign array values or object properties to multiple variables at once.
Destructuring objects
Before destructuring came, if we wanted to have specific properties of an object mapped to normal variables, we had to assign every property separately.
const obj = {
enabled: true,
darkMode: false,
stayLoggedIn: true
}
const enabled = obj.enabled
const darkMode = obj.darkMode
const stayLoggedIn = obj.stayLoggedIn
Now with object destructuring, this can be shortened down to just one line instead of three, check it out!
const obj = {
enabled: true,
darkMode: false,
stayLoggedIn: true
}
const { enabled, darkMode, stayLoggedIn } = obj
console.log(enabled, darkMode, stayLoggedIn)
// Output:
true
false
true
As you can see, all properties got mapped to variables with the same name. If you don't want to have your variables named exactly like the properties, you can use a colon (:
) to map the right value to another variable name.
const obj = {
enabled: true,
darkMode: false,
stayLoggedIn: true
}
const { enabled: activated, darkMode, stayLoggedIn } = obj
console.log(enabled, activated)
// Output:
undefined
true
As you can see, the obj.enabled
property got mapped to the variable activated
instead of enabled
. You can easily decide the names for your variables while keeping it's simplicity.
You can also destructure nested properties, it works just like you would expect it to.
const obj = {
enabled: true,
settings: {
darkMode: false,
stayLoggedIn: true
}
}
const { settings: { darkMode, stayLoggedIn } } = obj
console.log(darkMode, stayLoggedIn)
// Output:
false
true
In this example, we mapped the nested properties to variables and didn't bother with any other values, they do not get deleted or anything by this, they just don't get mapped.
Destructuring can also be used to access properties of primitive types, like String.length
.
const string = 'awesome'
const { length } = string
console.log(length)
// Output:
7
Destructuring arrays
Arrays can also be destructured, they are guaranteed to preserve their order which means you can destructure it just like an object.
const date = ['09', '04', '2001']
const day = date[0]
const month = date[1]
const year = date[2]
As you can see, this is nearly the same as it was with the objects, before destructuring, we had to assign them separately after another which can take up a lot of lines in your code.
const date = ['09', '04', '2001']
const [day, month, year] = date
console.log(day, month, year)
// Output:
09
04
2001
You can also skip values by not specifying a variable name.
const date = ['09', '04', '2001']
const [day, , year] = date
console.log(day, year)
// Output:
09
2001
Nested arrays can also be destructured, just like nested objects.
const nested = ['A', 'B', ['C', 'D'], 'E']
const [a, b, [c, d], e] = nested
console.log(a, b, c, d, e)
// Output:
'A'
'B'
'C'
'D'
'E'
Object destructuring and array destructuring can be combined into one assignment and you can even use default parameters when destructuring, let me show you!
const obj = {
enabled: true,
darkMode: false,
roles: ['user', 'admin', 'moderator']
}
const {
enabled,
date = new Date(),
darkMode,
roles: [userRole, , moderatorRole]
} = obj
console.log(date)
// Output:
Wed Jun 17 2020 09:52:20 GMT+0200 (Central European Summer Time)
Rest parameters
Instead of allowing you to unpack or update objects and arrays, rest parameters makes it easy for you to create arrays with an indefinite amount of arguments.
The syntax is the same as it is for spreading (...
).
const foo = (...args) => console.log(args)
foo('A', 'B', 'C', 'D')
// Output:
['A', 'B', 'C', 'D']
As you can see, all arguments passed to foo
were aggregated into the array args
.
Rest parameter syntax can only be used in two ways, as the last parameter, catching all arguments that are not declared, or as the only parameter of a function, catching all arguments as shown above.
const foo = (first, second, ...args) => console.log(first, second, args)
foo('A', 'B', 'C', 'D')
// Output:
A
B
['C', 'D']
That's not everything, though!
const { enabled, ...originalObject } = {
enabled: true,
darkMode: false,
stayLoggedIn: true
}
console.log(enabled, originalObject)
// Output:
true
{darkMode: false, stayLoggedIn: true}
As you can see, objects can also be destructured using rest parameter syntax, but it is also possible with arrays, let me show you!
const [first, second, ...rest] = ['A', 'B', 'C', 'D']
console.log(first, second, rest)
// Output:
A
B
['C', 'D']
TLDR:
- Spreading can be used to unpack arrays and objects
- Destructuring can be used to create multiple variables from arrays or objects
- Rest parameters can be use to create arrays with indefinite size
You should definitely be using them in your next project! Have fun experimenting with these three techniques.
Top comments (2)
Good articles, really useful, but i found some typo, ๐ that is
..args
instead of...args
๐๐Thank you! Fixed!