Skip to main content

Spread and Rest Syntax

The modern standard has a new syntax for work with iterables such as a string, array or object. Its functionality and name depend on where it is used.

spread: passing arguments

The ... (spread) operation makes it possible to spread a collection of elements (array, string or object) to the places where a set of single values is expected. Of course, some restrictions apply; for example, you cannot spread an array to an object, and vice versa.

Imagine an apple crate. When you put the crate on the floor without taking out the apples, you get an array of values. If you empty the crate onto the floor, you will initiate spreading, i.e. generate a set of individual values.

The only difference is that in JavaScript, spreading does not change the original collection, that is, a copy of each element is made. After spreading, there will be a crate full of apples and a copy of each apple on the floor.

For example, the Math.max(arguments) method looks for and returns the largest of the arguments (numbers), that is, it expects not an array of values, but an arbitrary number of arguments.

const temps = [14, -4, 25, 8, 11];

// The console will have an array,
console.log(temps);
// ❌ This will not work because you are passing the entire array
console.log(Math.max(temps)); // NaN

// The console will have a set of separate numbers
console.log(...temps);
// ✅ Spread the collection of elements as separate arguments
console.log(Math.max(...temps)); // 25

That is, Math.max(...[14, -4, 25, 8, 11]) after interpretation turns into Math.max(14, -4, 25, 8, 11); ... syntax returns an unpacked array, that is, spreads its elements as individual arguments.

spread: creating a new array

The ... (spread) operation enables you to create a copy of an array or "bond" an arbitrary number of arrays together to make a new one. Previously, the slice() and concat() methods were used for this purpose, but the spread operation does the same in a more concise way.

const temps = [14, -4, 25, 8, 11];

// This is an exact but independent copy of the temps array
const copyOfTemps = [...temps];
console.log(copyOfTemps); // [14, -4, 25, 8, 11]

In the example above, you have a crate of apples, temps, and you want to make its exact copy. Take an empty crate and place apples from the original temps crate into it, i.e. spread it to another collection. In this case, the temps crate will not change, it will still contain apples, and the new crate will contain their exact copies.

In the following example, you will pour apples from the two crates into a new one. The original crates (arrays) will not change, and the new one will contain copies of all their apples (elements). The spread order is important because it affects the order of elements in the new collection.

const lastWeekTemps = [14, 25, 11];
const currentWeekTemps = [23, 17, 18];
const allTemps = [...lastWeekTemps, ...currentWeekTemps];
console.log(allTemps); // [14, 25, 11, 23, 17, 18]

spread: creating a new object

The ... (spread) operation enables you to spread the properties of an arbitrary number of objects to a new one.

const first = { propA: 5, propB: 10 };
const second = { propC: 15 };
const third = { ...first, ...second };
console.log(third); // { propA: 5, propB: 10, propC: 15 }

Spread order matters. Object property names are unique, so the properties of the sprayed object can overwrite the value of an existing property if their names are the same.

const first = { propA: 5, propB: 10, propC: 50 };
const second = { propC: 15, propD: 20 };

const third = { ...first, ...second };
console.log(third); // { propA: 5, propB: 10, propC: 15, propD: 20 }

const fourth = { ...second, ...first };
console.log(fourth); // { propA: 5, propB: 10, propC: 50, propD: 20 }

If the apples in the crate had labels, there could not be two apples with the same labels in the same crate. Therefore, when emptying the second box, all the apples with labels matching those in the new crate will replace those that are already there.

While spreading, you can add properties to any location. The main thing to remember is that the property name is unique and that its value can be overwritten.

const first = { propA: 5, propB: 10, propC: 50 };
const second = { propC: 15 };

const third = { propB: 20, ...first, ...second };
console.log(third); // { propA: 5, propB: 10, propC: 15 }

const fourth = { ...first, ...second, propB: 20 };
console.log(fourth); // { propA: 5, propB: 20, propC: 15 }

const fifth = { ...first, propB: 20, ...second };
console.log(fifth); // { propA: 5, propB: 20, propC: 15 }

rest: collecting all function arguments

The ... (rest) operation makes it possible to collect a group of independent elements into a new collection. Syntactically, this is a twin of the spread operation, but it is easy to distinguish them: spread is when ... is on the right-hand side of the assignment operation, and rest is when ... is on its left-hand side.

Let's go back to our apples. If there are apples on the floor and you have an empty crate, the rest operation will help you "collect" the apples into the crate. In this case, the original apples will remain on the floor, and there will be a copy of each apple in the crate.

One of the uses of the rest operation is to create functions that can include an arbitrary number of arguments.

// How to declare function parameters so
// that any number of arguments can be passed?
function multiply() {
// ...
}

multiply(1, 2);
multiply(1, 2, 3);
multiply(1, 2, 3, 4);

If you remove all the "syntax noise" and look at the function arguments and parameters, you will see the arguments on the right-hand side of the assignment operation and the parameters on its left-hand side, because the values of the arguments are assigned to the declared parameters. So you can "collect" all the function arguments into one parameter using the rest operation.

function multiply(...args) {
console.log(args); // array of all arguments
}

multiply(1, 2);
multiply(1, 2, 3);
multiply(1, 2, 3, 4);

The parameter name can be arbitrary. Most often it is called args, restArgs or otherArgs, short for arguments.

rest: collecting part of function arguments

The ... (rest) operation also serves to collect into an array only the required part of the arguments by declaring parameters before such "collection".

function multiply(firstNumber, secondNumber, ...otherArgs) {
console.log(firstNumber); // First argument value
console.log(secondNumber); // Second argument value
console.log(otherArgs); // Array of other arguments
}

multiply(1, 2);
multiply(1, 2, 3);
multiply(1, 2, 3, 4);

All arguments with declared parameters will pass their values to them, whereas the remaining arguments will be placed in an array. The rest operation collects all the remaining arguments and therefore must be positioned last in the function signature, otherwise there will be an error.