- Function argument list (
myFunction(a, ...iterableObj, b)
) - Array literals (
[1, ...iterableObj, '4', 'five', 6]
) - Object literals (
{...obj, key: 'value'}
)
Replace apply()
1
2
3
| function myFunction(x, y, z) { }
let args = [0, 1, 2];
myFunction.apply(null, args);
|
can be written as
1
2
3
| function myFunction(x, y, z) { }
let args = [1, 2, 2];
myFunction(...args);
|
can be used multiple time.
1
2
3
| function myFunction(v, w, x, y, z) { }
let args = [0, 1];
myFunction(-1, ...args, 2, ...[3]);
|
Apply for new operator
When calling a constructor with new it’s not possible to directly use an array and apply() (apply() does a [[Call]] and not a [[Construct]]).
However, an array can be easily used with new thanks to spread syntax:
1
2
| let dataFields = [1970, 0, 1]; // 1 Jan 1970
let d = new Date(...dataFields);
|
Copy an array
1
2
| let arr = [1,2,3];
let arr2 = [...arr]; // like arr.slice()
|
1
2
3
| arr2.push(4);
// arr2 becomes [1,2,3,4]
// arr remains unaffected
|
Maybe Unsuitable for copying multimenstional arrays
Spread syntax effectively goes one level deep while copying an array.
(The same is true with Object.assign()
.)
1
2
3
4
5
6
7
8
9
| let a = [[1], [2], [3]];
let b = [...a];
b.shift().shift();
// 1
// Oh no! Now array 'a' is affected as well:
a
// [[], [2], [3]]
|
A better way to concatenate arrays
1
2
3
4
5
6
7
8
| let arr1 = [0, 1, 2];
let arr2 = [3, 4, 5];
// Append all items from arr2 onto arr1
arr1 = arr1.concat(arr2);
arr1 = [...arr1, ...arr2];
// Note: Not to use const otherwise, it will give TypeError (invalid assignment)
|
Array.propotype.unshift()
is often used to insert an array of values at the start of an existing array.
1
2
3
4
5
| // Prepen all items from arr2 onto arr1
Array.prototype.unshift.apply(arr1, arr2);
// arr1 is now [3, 4, 5, 0, 1, 2]
arr1 = [...arr2, ...arr1]
|
Unlike unshift()
, this creates a new arr1
, and does not modify the original arr1
array in-place.
Spread in object literals
The Rest/Spread Properties for ECMAScript proposal (ES2018) added spread properties to object literals. It copies own enumerable properties from a provided object onto a new object. Shallow-cloning (excluding prototype) or merging of objects is now possible using a shorter syntax than Object.assign().
1
2
3
4
5
6
7
8
| let obj1 = { foo: 'bar', x: 42 };
let obj2 = { foo: 'baz', y: 13 };
let cloneObj = { ...obj1 };
// Object { foo: "bar", x: 42 }
let cloneObj = { ...obj1, ...obj2 };
// Object { foo: "baz", x: 42, y: 13 }
|
Note that Object.assign() triggers setters, whereas spread syntax doesn’t.
Note that you cannot replace or mimic the Object.assign()
function:
1
2
3
4
5
6
| let obj1 = { foo: 'bar', x: 42 };
let obj2 = { foo: 'baz', y: 13 };
const merge = ( ...objects ) => ( { ...objects } );
let mergeObj1 = merge (obj1, obj2);
// Object { 0: { foo: 'bar', x: 42}, 1: { foo: 'baz', y: 13 } }
|
Only for iterables
Spread syntax (other than in the case of spread properties) can only be applied to iterable objects like Array, or with iterating functions such as map()
, reduce()
, and assign()
. Many objects are not iterable, including Object
:
1
2
| let obj = {'key1': 'value1'};
let array = [...obj]; // TypeError: obj is not iterable
|
To use spread syntax with these objects, you will need to provide an iterator function.