DEV Community

Cover image for JavaScript Spread and Rest Operators: An Essential Guide for Beginners
abhijitdotsharma
abhijitdotsharma

Posted on • Updated on

JavaScript Spread and Rest Operators: An Essential Guide for Beginners

Two JavaScript operators with same syntax but totally different working.

Spread

Spread operator(...) is a tool in modern JavaScript that is used when working with arrays, objects, and function calls. Spread allows objects and iterables (arrays for now) to be unpacked.

Too techie? Spread helps us expand iterables into individual elements.

Spread with Arrays

Using spread with arrays, is something that you'll see almost every time. So focus!

const tools = ['hammer', 'screwdriver']
const otherTools = ['wrench', 'saw']

const allTools = [...tools, ...otherTools]
console.log(allTools)

//Output : ['hammer', 'screwdriver', 'wrench', 'saw']
Enter fullscreen mode Exit fullscreen mode

In the example above, we see that we can unpack elements from array into another array.
This is super useful in cases, where we want to achieve immutability, like in React Applications.

Spread with Objects

Like arrays, spread is used to copy and update objects. This was earlier done using Object.assign(), but spread make it simple.

const ogObject = { language: 'english', darkMode: false }
const newObject = {...ogObject}

console.log(newObject)
//Output: {language: 'english', darkMode: false}
Enter fullscreen mode Exit fullscreen mode

Similar to arrays, this creates a shallow copy, and the nested objects inside (if there are any) will still be passed by reference.

Spread shines when we have to add or modify properties on an existing object without mutating it.

const player = {
    id: 2,
    name: 'Abhi',
}

const updatedPlayer = { ...player, isLoggedIn: true }

console.log(updatedPlayer)
//Output: {id: 2, name: 'Abhi', isLoggedIn: true}
Enter fullscreen mode Exit fullscreen mode

One Important concept to remember with spread and nested objects is, when copying object, remember to spread the nested objects as well.

const player = {
    id: 2,
    name: 'Abhi',
    team: { 
       name: 'Avengers',
       city: 'LA',
    }
}
Enter fullscreen mode Exit fullscreen mode

If the player is now the leader of the team and you want to update that inside the team property, which itself is an object.
Doing this is wrong

const updatedPlayer = { ...player, team: {position: 'captain'} }
Enter fullscreen mode Exit fullscreen mode

This will result in

updatedPlayer -> 
id: 2,
name: 'Abhi',  
team: { position: 'captain' }
Enter fullscreen mode Exit fullscreen mode

See how the old fields are overwritten, to do it without mutating we have to

const updatedPlayer = { 
    ...player, //copy entire player Object
    team: { 
      ...player.team, //copy entire player.team Object
      position: 'captain',//and then update/add a property on top of old properties
    }
}
Enter fullscreen mode Exit fullscreen mode

Spread in Function Calls

Let's define a simple function that take 3 parameters and adds them

function addThree(a, b, c){
    return a + b + c ;
}
Enter fullscreen mode Exit fullscreen mode

To pass the values individually to the function call, you can do this:

addThree(2, 4, 6)
//output
//10๐Ÿ‘Œ
Enter fullscreen mode Exit fullscreen mode

Suppose you have an array that has the values that you want to pass. You can do something like this:

const nums = [2, 4, 5 ]
addThree(nums[0], nums[1], num[2])
Enter fullscreen mode Exit fullscreen mode

But this is not very efficient. Instead, you can use the spread operator to spread the elements of the nums array as individual arguments to the addThree function:

addThree(...nums)
Enter fullscreen mode Exit fullscreen mode

This allows us to pass the values individually, shortening our code and increasing its readability

Note: The spread operator creates a shallow copy of an array or object, meaning that any top-level properties will be cloned, but any nested objects or arrays will still be passed by reference. This is important to keep in mind when using the spread operator to make copies of objects that contain nested objects or arrays.

Rest

The rest operator (...) is used to represent an indefinite number of arguments as an array. It is usually used in function definitions to allow the function to accept any number of arguments.

function sum(...nums) {
  let result = 0;
  for (const num of nums) {
    result += num;
  }
  return result;
}

console.log(sum(1, 2, 3, 4));
// Output: 10
Enter fullscreen mode Exit fullscreen mode

This was done earlier using the arguments variable, but it cannot be used with newer arrow functions and additionally arguments is not a true array so map and filter doesnt apply on it.

Rest to destructure Arrays and Objects

Destructuring Arrays with Rest
Here's an example of using the rest operator to destructure an array:

const numbers = [1, 2, 3, 4, 5];
const [first, second, ...others] = numbers;

console.log(first);
// Output: 1
console.log(second);
// Output: 2
console.log(others);
// Output: [3, 4, 5]
Enter fullscreen mode Exit fullscreen mode

Destructuring Objects with Rest
You can also use the rest operator to destructure objects. Here's an example:

const person = {
  name: 'John',
  age: 30,
  occupation: 'developer',
  location: 'New York'
};

const { name, age, ...otherInfo } = person;

console.log(name);
// Output: 'John'
console.log(age);
// Output: 30
console.log(otherInfo);
// Output: { occupation: 'developer', location: 'New York' }
Enter fullscreen mode Exit fullscreen mode

In the example above, the rest operator is used to assign the remaining properties of the person object to the otherInfo variable.

tl;dr:

While the rest operator collects an indefinite number of arguments into an array, the spread operator extracts elements from an array (or properties from an object) and expands them into individual elements or properties.

Be sure not to confuse function parameters and function arguments:

function foo (...bar) {} // rest
foo(...baz) // spread
Enter fullscreen mode Exit fullscreen mode

There's also rest in destructuring, which should not be confused with literal spreading:

const { a, b, ...others } = { a:1, b:2, c:3, d:4, e:5 } // rest
const aToE = { a, b, ...others } // spread
Enter fullscreen mode Exit fullscreen mode

Destructuring is used to create varibles from array items or object properties.
Spread syntax is used to unpack iterables such as arrays, objects, and function calls.

Overall, the spread and rest operators are useful tools for working with arrays, objects, and function arguments in JavaScript. They can help you write more concise and readable code. Visit MDN if you ever want to learn more

follow me on twitter , LinkedIn

Top comments (9)

Collapse
 
tookaynet profile image
Dave Martin

Am I missing something or should the references to ...user and updatedPlayer actually be player and updatedUser in

const player = {
id: 2,
name: 'Abhi',
}
const updatedPlayer = { ...user, isLoggedIn: true }
console.log(updatedUser)

?

Collapse
 
abhijitdotsharma profile image
abhijitdotsharma

I have corrected the typo
Thanks for the heads up, much appreciated.

Collapse
 
amircahyadi profile image
Amir-cahyadi

๐Ÿ‘โค๏ธ

Collapse
 
fruntend profile image
fruntend

ะกongratulations ๐Ÿฅณ! Your article hit the top posts for the week - dev.to/fruntend/top-10-posts-for-f...
Keep it up ๐Ÿ‘

Collapse
 
abhijitdotsharma profile image
abhijitdotsharma

Didn't know this till I saw your comment, thanks a lot.

Collapse
 
zakariya09 profile image
Zakariya Khan

Awesome post. Thank you.

Collapse
 
abhijitdotsharma profile image
abhijitdotsharma

I am glad it helped.

Collapse
 
extinctsion profile image
Aditya Sharma

I think this post is also extendable to Python 3.x version in which they have introduced the same. Great explanation.

Collapse
 
abhijitdotsharma profile image
abhijitdotsharma

Glad it helped