The spread syntax allows us to break up a collection of objects, like arrays, into individual arguments or insert them into a different iterable object, like an array.
With the 2018 version of JavaScript, we can also spread properties of an object into another object, with keys and values spread into another object. The spread syntax is denoted by three periods before your object.
For example, we can write:
...arr
The spread syntax works by copying the values of the original array and then inserting them into another array, or putting them in the order they appeared in the array as the list of arguments in a function in the same order.
When the spread operator is used with objects, the key-value pairs appear in the same order they appeared in the original object.
We can use the spread syntax to spread an array of values as arguments of a function. For example, we can write:
const arr = [1,2,3];
const add = (a,b,c) => a+b+c;
add(...arr) // returns 6
In the example above, the spread operator spreads the variables into the argument in the same order they appeared in the array. So 1 is passed into a
, 2 is passed into b
, and 3 is passed into c
.
Spread Arrays
For arrays, we can also use the spread syntax to insert one array’s values into another array. For example, we can write:
const arr = [1,2,3];
const arr2 = ['a','b','c',...arr,'d']; // arr2 is ['a','b','c',1,2,3,'d']
As we can see, the spread operator inserts the values exactly where we spread the array, in the same order they appeared in the array.
So, 1 is inserted between a
and d
, then 2 is inserted between 1 and d
, and 3 is inserted between 2 and d
. The result is that we copied an array’s values into another array with the spread operator in the same order they appeared in, and exactly where you put the array spread expression.
Without the spread operator, we have to write loops to insert them into the position we want. We slice
the array into two and then call concat
on the three parts, then assign the result to the array you inserted the stuff into. It sounds painful just thinking about it.
Note that with the spread operator, only the first level of the array is spread. If we have nested or multi-dimensional arrays, it’s going to copy the references as-is. It will not do anything to nested items.
With ES2018, we can do the same thing with objects, like the following:
const obj = {a: 1, b: 2};
let objClone = { ...obj }; // objClone is {a: 1, b: 2}
This creates a shallow copy of the object. It means that only the first level of the object is copied.
For nested objects, it’s going to copy the references as-is. It will not do anything to nested items. The top-level keys and values of the object will be copied to objClone
.
So, if we have nested objects, we get:
const obj = {
a: 1,
b: {
c: 2
}
};
let objClone = {
...obj
};
console.log(objClone)
In objClone
, we get:
{
a: 1,
b: {
c: 2
}
}
So, nested objects will reference the same ones as the original.
The spread operator can be used as an alternative to other functions that existed before.
For example, we can use it to replace the apply
function for passing in arguments to a function. The apply
function takes an array of arguments for the function it’s called on as the second argument.
With the apply
function, we call it as follows:
const arr = [1,2,3]
const sum = (a,b,c)=> a+b+c;
sum.apply(null, arr); // 6
With the spread syntax, we can write the following instead:
const arr = [1,2,3]
const sum = (a,b,c)=> a+b+c;
sum(...arr)
The spread operator also work with strings. We apply the spread operator to strings, we get an array with the individual characters of the string.
For example, if we write:
const str = 'abcd';
const chars = [...str];
We get [“a”, “b”, “c”, “d”]
as the value of chars
.
Using Spread Operator Multiple Times
We can use the spread syntax multiple times in one place. For example, we can have the following:
const arr = [1,2,3];
const arr2 = [4,5];
const sum = (a,b,c,d,e,f)=> a+b+c+d+e+f;
sum(...arr, ...arr2, 6)
As usual, the spread syntax will spread the array of numbers into arguments of the array in the order as they appeared in.
So, sum(…arr, …arr2, 6)
is the same as sum(1,2,3,4,5,6)
.
1, 2, and 3 are the first three arguments, which are the entries of arr
in the same order, and 4 and 5 are the fourth and fifth arguments, which are spread after 1, 2, and 3.
Then, in the end, we have 6 as the last argument. We can also see the spread syntax work with the normal function call syntax.
Use It in Constructors
We can use the spread operator as arguments for object constructors. For example, if we want to create a new Date
object, we can write:
let dateFields = [2001, 0, 1];
let date = new Date(...dateFields);
The items in the dateFields
array are passed into the constructors as arguments in the order they appeared in. The alternative way to write that would be much longer, something like:
let dateFields = [2001, 0, 1];
const year = dateFields[0];
const month = dateFields[1];
const day = dateFields[2];
let date = new Date(year, month, day);
Copying Items
The spread syntax can also be used to make a shallow copy of an array or an object as it works by creating copies of the top-level elements of an array or key-value pairs of an object and then inserting them into the place you used the spread operator with.
For copying arrays, we can write:
const arr = [1, 2, 3];
const arr2 = [...arr, 4, 5];
The above example, arr2
, is [1,2,3,4,5]
, while arr1
is still [1,2,3]
.
arr1
is not referenced by arr2
because the spread operator actually makes a copy of the array and then inserts the values. Note that this doesn’t work with multi-dimensional arrays as it only makes copies of the top-level elements.
We can apply the spread syntax multiple times in one array or object. An example for array would be:
let arr = [1, 2, 3];
let arr2 = [4, 5];
let arr3 = [...arr2, ...arr];
In the above example, we get [4,5,1,2,3]
. arr1
and arr2
are unaffected as a copy of the values from arr1
and arr2
are inserted into arr3
.
Spread Operator and Objects
With ES2018, the spread operator works with object literals. Then, key-value pairs of an object can be inserted into another object with the spread operator.
If there are two objects with the same key that the spread operator is applied to in the same object, the one that’s inserted later will overwrite the one that’s inserted earlier.
For example, if we have the following:
let obj1 = {foo: 'bar', a: 1};
let obj2 = {foo: 'baz', b: 1};
let obj3 = {...obj1, ...obj2 }
Then we get {foo: “baz”, a: 1, b: 1}
as the value of obj3
because obj1
is spread before obj2
.
They both have foo
as a key in the object. First, foo: 'bar'
is inserted by the spread operator to obj3
. Then, foo: 'baz'
overwrites the value of foo
after obj2
is merged in, as it has the same key foo
but inserted later.
This is great for merging objects as we don’t have to loop through the keys and put in the values, which is much more than one line of code.
One thing to note is that we can’t mix the spread operator between regular objects and iterable objects. For example, we will get TypeError
if we write the following:
let obj = {foo: 'bar'};
let array = [...obj];
Conclusion
As we can see, the spread syntax is a great convenience feature of JavaScript. It lets us combine different arrays into one.
Also, it lets us pass arrays into a function as arguments with just one line of code. With ES2018, we can also use the same operator to spread key-value pairs into other objects to populate one object’s key-value pairs into another object.
The spread operator works by copying the top-level items and populating them in the place you use the spread operator, so we can also use it to make shallow copies of arrays and objects.