Exploring the Spread Operator and Rest Parameter in JavaScript

The spread operator has many use cases. Let’s go over a few of them

George Roubie
Better Programming

--

Hand reaching out toward the sky
Photo by Drew Saurus on Unsplash.

In this article, I am going to explain what the spread operator and rest parameter are in JavaScript. But first, let’s see what a logical operator is in JavaScript.

Logical Operators

&& and || are known as logical operators. The logical operators in JavaScript do not return only boolean like in other programming languages. The logical operators in JavaScript return a value. That’s why many developers call them select operators.

Rules:

  • truthy && whatever = whatever
  • falsy && whatever = falsy
  • truthy || whatever = truthy
  • falsy || whatever = whatever

But what are truthy and falsy? A value is truthy if you pass it in the Boolean constructor as an argument and it returns true. If it returns false, it is falsy.
A simpler rule is that the values false, null, undefined, 0, -0, ‘’, NaN, 0n, and -0n are falsy, while everything else is truthy.

const user = null;
const currentUser = user || {};

The example above is a simple way to add a default value. Because the user is null (falsy) the currentUser will be {}.

Spread Operator

The spread operator is an operator like +, -, /, etc. that takes an iterable (something that we can loop through) and expands it to individual elements. The syntax is three dots (...) and there are many use cases.

Shallow copy an object

Objects are non-primitive types that are saved by reference. If an object is equal to another object, when you change the first object, the second object is automatically changed.

const user1 = { name: 'George', surname: 'ruby' };
const user2 = user1;
user2.surname = 'Roubie';

In the example above, the surname in user1 is also changed. We can use the spread operator to fix it.

const user1 = { name: 'George', surname: 'ruby' };
const user2 = { ...user1 };
user2.surname = 'Roubie';

We can optimize the code above like this:

const user1 = { name: 'George', surname: 'ruby' };
const user2 = { ...user1, surname: 'Roubie' };

This code works because if you have the same key twice inside an object, the last one wins. This feature is very useful in state management techniques.

A shallow copy means that if there are nesting objects inside the copied object, the reference will remain.

const roles = { isAdmin: true };
const user1 = { name: 'George', surname: 'Roubie', role: roles };
const user2 = { ...user1 };
user2.role.isAdmin = false;

In the example above, the role is also changed in user1, so be careful.

Combining objects

With the spread operator, we can combine as many objects as we want to a new one.

const userInfo = { name: 'George', surname: 'Roubie' };
const userRoles = { roles: ['admin', 'it'] };
const token = { accessToken: '123', refreshToken: '456' };
const currentUser = { ...userInfo, ...userRoles, ...token };

Conditionally add properties to an object

You can easily add properties to an object with the help of the logical operator && and the spread operator.

const getRole = () => 'admin';
const user = {
name: 'George',
surname: 'Roubie',
...(getRole() === 'admin' && { admin: true })
};

Because getRole() === 'admin' returns true, && returns { admin: true }. That’s why admin: true is added in the user object.

const getRole = () => 'dev';
const user = {
name: 'George',
surname: 'Roubie',
...(getRole() === 'admin' && { admin: true })
};

Now getRole() === 'admin' returns false and && returns false. But if you spread the false (e.g. { ...(false) }), the spread operator will return nothing ({}). That’s why nothing is added in the user object.

Copying an array (shallow)

Arrays are non-primitive types like objects. If an array is equal to another array, when you change the first array, the second array is automatically changed.

const a = [1, 2, 3];
const b = [...a];
b.push(4);

The code above can be also implemented with the slice method.

const a = [1, 2, 3];
const b = [...a, 4];

But with the slice method, we can’t add a value when we copying an array, as we did in the example above.

This copy is shallow, so if you have objects or arrays inside the array, the reference will remain.

const data = { test: 1 };
const arr1 = [1, 2, 3, data];
const arr2 = [...arr1];
arr2[3].test = 3;

In this example, arr1 and arr2 will have the value { test: 3 } in the third index of the array because the copy is shallow.

Concatenating arrays

With the spread operator, we can concatenate as many arrays as we want to a new one.

const a = [1, 2, 3];
const b = [4, 5, 6];
const c = [7, 8, 9];
const d = [...a, ...b, ...c];

If we want to concatenate two arrays, we can also do it with the concat method, but the concat method can only concatenate two arrays. With the spread operator, we can concatenate as many arrays as we want and we can also add values between the arrays, which we can’t do with the concat method.

const a = [1, 2, 3];
const b = [5, 6, 7];
const c = [9, 10, 11];
const d = [0, ...a, 4, ...b, 8, ...c, 12];

Using an array as an argument

Because the spread operator expands an array to individual elements, we can pass an array as an argument in a function. First, let’s see how we can do it without the spread operator.

const userInfo = ['George', 'Roubie'];
const getUser = function(name, surname) {
console.log(name, surname);
};
getUser(userInfo[0], userInfo[1]);

With the spread operator, we can easily do it like this:

const userInfo = ['George', 'Roubie'];
const getUser = function(name, surname) {
console.log(name, surname);
};
getUser(...userInfo);

This is very helpful when there are multiple arguments.

Rest Parameter

The syntax is the same as the spread operator’s, but it’s not an operator. In fact, it’s the exact opposite of the spread operator and combines the remaining elements into a single element.

const user = function (name, age, ...hobbies) {
console.log(name);
console.log(age);
console.log(hobbies);
}
user('George', 30, 'coding', 'killing zombies');

The hobbies parameter is now an array with the value of ['coding', 'killing zombies'].

var user = function (name, age, ...hobbies) {
console.log(name);
console.log(age);
console.log(hobbies);
}
user('George', 30);

When there are no values, the rest parameter makes hobbies an empty array. This is very helpful because we don’t have to worry when we don’t add extra values.

--

--

Experienced Software Engineer with more than 10 years of experience, specialized in Front-End Web technologies, with strong foundations in programming.