Spread and Rest Operators
Introduction: Same Syntax, Different Jobs
In our previous lesson, we looked at how to use the "rest" syntax within destructuring to collect the remaining items of an array. You might have noticed that we used three dots (...) to do that. Today, we are going to explore this syntax in much more detail. In modern JavaScript, these three dots have two distinct roles depending on where you use them: they either "spread out" data or "gather up" data.
When we use this syntax to expand an array or an object into a new one, we call it the spread operator. When we use it to collect multiple values into a single variable, we call it rest parameters. Understanding the difference between these two is a major step in writing clean, professional code. As always, the examples we cover today will work perfectly in your CodeSignal IDE, where the environment is already set up for you.
Spreading Arrays
The most common use for the spread operator is working with arrays. Imagine you have two separate lists of numbers and you want to join them into one larger list. In the past, this required using specific array methods that could be difficult to read. With the spread operator, you can "pour" the contents of one array into another.
Output:
In this code, the merged array is created by spreading out all the elements from array a and all the elements from array b. Notice that we also added the number 6 at the very end. The spread operator essentially takes the items out of their original containers and places them individually into the new array. This is an excellent way to combine data or add new items to a list without modifying the original variables.
Spreading Objects
Just as we can spread arrays, we can also spread objects. When you spread an object into a new one, JavaScript takes all the key-value pairs from the source object and copies them into the new one. This is a very fast way to create a shallow copy of an object.
A shallow copy means that only the top-level properties are copied. If the original object contains nested objects or arrays, the new copy will still point to those same nested items in memory rather than creating brand-new versions of them.
Output:
In this example, the copy object starts with everything inside the original object. By adding location after the spread operator, we create a new object that has three properties instead of two. This technique is incredibly helpful because it allows us to build new data structures based on existing ones with very little code.
Creating Immutable Updates
In modern JavaScript development, we often follow a rule called immutability. This means that instead of changing an existing object or array directly, we create a new copy with the updated information. This makes our code much more predictable and easier to debug. We can combine everything we have learned about spreading objects and arrays to perform these updates safely.
Output:
In this piece of code, we created an updated object. We used ...original to pull in the existing name and balance. Then, we manually set balance to a new value, which overwrites the old one in the new object. For the tags property, we created a brand new array by spreading the old tags and adding a new string, "verified". Because we did this, the original object stays exactly the same, while our updated object holds the new data.
Rest Parameters: Gathering Function Arguments
Now let's look at the other side of the three dots: rest parameters. As we discussed when learning about destructuring, the "rest" syntax is used to gather multiple items together. While the spread operator expands data, rest parameters gather multiple individual values into a single array. You will use this most often in function definitions when you do not know exactly how many arguments a user might pass in.
Output:
The function logAll takes one regular parameter called label. Everything else provided to the function is gathered by the ...values syntax into an array. When we call the function with four numbers, JavaScript puts those numbers into the values array for us. This makes the function very flexible because it can handle any number of inputs without needing a long list of parameters.
Spreading Into Function Calls
The final way we use this syntax is by spreading an array directly into a function call. Some built-in JavaScript functions expect a list of individual arguments rather than a single array. If you have your data stored in an array, you can use the spread operator to "unpack" it for the function.
Output:
The Math.max function is designed to look at individual numbers to find the largest one. It does not know how to read an array directly. By using ...nums, we turn the array into three separate arguments: 10, 20, and 30. The function then processes them correctly and returns the highest value. This saves you from having to manually pull items out of the array by their index.
Summary And Next Steps
In this lesson, we explored the versatility of the three dots ... syntax. You learned how the spread operator allows you to merge arrays and create updated copies of objects without changing the original data. You also saw how rest parameters can gather multiple function arguments into a single array, and how you can spread an array into a function call to unpack its values.
These techniques are essential for writing "clean" code that is easy for other developers to read and maintain. By focusing on creating new data instead of changing existing data, you prevent many common errors in JavaScript. Now that you understand how to spread and gather data, you are ready to put these skills to work in the practice exercises.
