Spreading, Destructuring and Rest Parameters in Javascript
Tags: javascript, ecmascript2015, features
Published: 2020-06-20 18:01:54

# 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

```js
// without spreading
const originalObject = { 
    enabled: true, 
    darkMode: false 
}
const secondObject = Object.assign({}, originalObject)
```

```js
// 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`.

```js
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.

```js
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:

```js
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

```js
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

```js
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:

```js
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.

```js
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!

```js
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.

```js
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.

```js
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`.

```js
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.

```js
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.

```js
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.

```js
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.

```js
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!

```js
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 (`...`).

```js
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.

```js
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!

```js
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!
```js
const [first, second, ...rest] = ['A', 'B', 'C', 'D']
console.log(first, second, rest)

// Output:
A
B
['C', 'D']
```

# TLDR:

- [Spreading](#Spreading) can be used to unpack arrays and objects
- [Destructuring](#Destructuring) can be used to create multiple variables from arrays or objects
- [Rest parameters](#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.