JavaScript: A Beginner’s Guide to Understanding Spread and Rest Syntax

Peter D'Elia
The Startup
Published in
5 min readApr 13, 2020

While working through Launch School’s JS101, these three dots, ..., kept popping up in code solutions to the small exercises. Coming from a background in Java and Python, I hadn’t seen this before, and its uses were opaque at first. Especially confusing was the fact that ... seemed to work in different ways, depending on the context. But after venturing to learn the names of its two uses (spread and rest) and what it does in its various contexts (explained below!), I now find the dots to be useful in my own programming practice.

Because it is not difficult to find explanations of spread and rest syntax elsewhere, this blog post strives to be different by making it as easy as possible to understand what the syntax does. Thus, it is intended for newcomers to the ideas of spread and rest.

We’ll look at pairs of examples whose only difference is the use of the three dots, to isolate how it changes the code’s behavior. The post is grouped by use case. And we will mostly focus on the uses of this syntax in relation to arrays, although it can be used with strings and objects as well.

What’s the difference between Rest and Spread?

The ... syntax is used in two ways in JavaScript: as a rest pattern and as the spread operator. As a spread operator, ... allows elements to be expanded out from an array, while as rest pattern, use of the dots places otherwise ungrouped elements into an array.

It might be helpful to realize that while rest and spread patterns exhibit opposite behaviors, they’re similar in that they both move elements in and out of arrays.

Spread Syntax for array copying and concatenation

Since ... syntax is used for two purposes, the only way to know what to expect of its behavior is to look at its context. Let’s start with examples of spread syntax:

let arr = ['a', 'b'];
let nestedArr = [arr];
let spreadCopy = [...arr];
nestedArr;
// [ [ 'a', 'b' ] ]
spreadCopy;
// [ 'a', 'b' ]

When ... is used within an array literal, each element of the array that follows the ... is expanded into the new array. In spreadCopy, the spread operator is used to make a copy of arr. By contrast, in nestedArr, the original array from arr is nested into another array. It might be helpful to think of the elements from arr as ‘breaking out’ of their brackets in spreadCopy. This is a nice concise way of making a copy of an array. Another example:

let arr1 = [1,2,3];
let arr2 = [4,5,6];
let doubleNested = [arr1, arr2];
let spreadArr = [...arr1, ...arr2];
doubleNested;
// [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]
spreadArr;
// [ 1, 2, 3, 4, 5, 6 ]

The example above shows how we can concatenate arrays using .... The difference between the output of doubleNested and spreadArr mirrors the behavior of the first example. Here, ... effectively removes the nested arrays and expands their elements into the outer array. Once again, it might be useful to think of the elements of arr1 and arr2 as breaking out of their brackets and all of their elements being inserted into the new array. The result is the same as calling arr1.concat(arr2).

Spread Syntax for splitting a string with an array literal

The same idea can be used for strings:

let string = 'hello';
let stringToArr = [string];
let spreadString = [...string];
stringToArr;
// [ 'hello' ]
spreadString;
// [ 'h', 'e', 'l', 'l', 'o' ]

In this example, using the ... is just like calling split('') on string. But the idea is similar to the above array examples: each character in the string is expanded into the new array. Once again, the difference is made clear when comparing the output of stringToArr to that of spreadString.

Spread Syntax for Passing Multiple Arguments in Function Calls

When used as an argument in a function call, the ... will expand a passed array into the function’s defined arguments. Here’s an example with and without spread syntax:

function spread(a, b, c) {
return a + b + c;
}
let numbers = [1, 2, 3];spread(...numbers);
// 6
spread(numbers);
// '1,2,3undefinedundefined'

When spread(...numbers) is called, the spread operator unpacks the three elements of numbers into arguments a, b, and c. They are then added together inside the function, and the sum is returned.

In contrast, when called without spread syntax, spread(numbers) retains the array passed by numbers and assigns it to variable a. It then interprets the + signs within the function declaration as string concatenation operators, implicitly converts numbers to a string, and concatenates the result with the undefined variables b and c, resulting in the strange-looking output above.

Rest Syntax for Handling Multiple Parameters in Function Definitions

We’ll now turn to rest syntax. In a function definition, the ... will place any number of passed arguments into a single array. Note that this behavior is the opposite of how we can use the spread operator in a function call. It’s important to remember that rest syntax must be the last parameter defined in the function. Here’s an example:

function rest(...args) {
console.log(args)
}
function withoutRest(args) {
console.log(args)
}
rest(1, 2, 3, 4);
// [ 1, 2, 3, 4 ]
withoutRest(1, 2, 3, 4);
// 1

Here, we can see that the call to rest with arguments 1, 2, 3, 4 outputs an array that concatenates all of the passed arguments. When we pass the same arguments to withoutRest, we get an output of 1. This is because the args parameter in this function definition only accepts a single argument and so ignores the subsequent arguments.

Rest Syntax for Assigning Multiple Elements to an Array Variable

Rest syntax can also be used in an array destructuring assignment. Here’s an example:

let arr = [1, 2, 3];
let [a, ...b] = arr;
let [c, d] = arr;
a;
// 1
b;
// [ 2, 3 ]
c;
// 1
d;
// 2

Just like in a function definition, using a rest element here will place multiple elements into an array. Thus, b is assigned to the rest of arr that is not captured by a. By comparison, d omits the dots and is therefore only assigned to the second element of arr. For more on array destructuring assignments, see the MDN docs.

A Final Thought

This was meant to be a concise and clear summary of the basics of spread and rest syntax, with a focus on understanding what the three dots are actually doing in code. To summarize, the syntax is a clean-looking way to copy and concatenate arrays, and to split characters in a string. It can also be a useful way to pass multiple elements in function calls and definitions, and in array destructuring assignments. As always, if you need more depth on the topic, consult the MDN docs.

--

--