The Spread Operator
ES2016 brings us many many goodies, one of which I came across a couple of days ago is the Spread Operator. I have become a big fan of it, not just because of its utility but also as it helps me to shorten my code. So what is it exactly?
Simply put, the spread operator allows an expression(that could be an array/object) to be expanded in places where multiple elements/variables/arguments are expected.
Syntax: ...
This will be best clarified by the following use-cases:
1. Merge Arrays/Objects
Lets assume we wish to insert an array, named center
in between another array, List
:
var list =[1, 2, 3, 9, 12]; var center = [7 , 8]; // with spread operator var result1 = [1, 2, 3, ...center, 9, 12]; // [1,2,3,7,8,9,12] // without spread operator var result2 = [1, 2, 3, center, 9,12]; // [1,2,3, [7,8], 9, 12]
As you can see above, the Spread operator inserts the individual elements similar to Array.splice() instead of inserting the array as a whole.
// For Objects const obj1 = { c: 3, d: 4 }; const obj2 = { a: 1, b: 2, ...obj1 }; // { a: 1, b: 2, c: 3, d: 4 } // When duplicate properties clash, the order of '...' determines the outcome. // The property put in last, wins! // when spread operator is last const obj2 = { b: 'x', c: 'y', ...obj1}; // {b: 'x', c: 3, d: 4 } // spread operator is first const obj2 = { ...obj1, b: 'x', c: 'y' }; // { b: 'x', c: 'y', d: 4 }
2. Call Functions with Arguments
function sum (x,y,z) { return x + y + z; } var args = [5,7,5]; sum(...args);
As you can see the spread operator expands the arguments passed to the function sum();
Until now, to do the same thing we had to use Function.prototype.call() or Function.prototype.apply() by passing a useless null parameter like
sum.apply(null, args);
or sum.call(null, args);
Similarly, JS functions like Math.max(...args);
can be called directly by passing an array instead of using call()/apply()
3. Eliminate duplicates from an Array:
const arr = [8, 5, 3, 5, 8, 3, 5]; const items = [...new Set(arr)]; console.log(items); // [ 8, 5, 3 ]
4. String to Character Array
The spread operator can be easily used to convert strings into character arrays.
const str = "hello"; const chars = [...str]; console.log(chars); // ['h', 'e',' l',' l', 'o']
5. Copying / Concatenating Arrays/Objects:
Traditionally to concatenate arrays, we used Array.prototype.concat() as follows:
var arr1 = ['a', 'b', 'c']; var arr2 = ['d', 'e', 'f']; arr = arr1.concat(arr2); // ['a', 'b', 'c', 'd', 'e', 'f']
The spread operator makes this as simple as
// For Arrays arr = [...arr1, ...arr2]; console.log(arr); // ['a', 'b', 'c', 'd', 'e', 'f'] // For Objects const obj1 = { a: 11, b: 22 }; const obj2 = { c: 33, d: 44 }; const merged = { ...obj1, ...obj2 }; // { a: 11, b: 22, c: 33, d: 44 }
To copy an Array/Object
The spread operator can be used to create a shallow copy of another array/object as follows
// For Arrays var arr1 = ['a', 'b', 'c']; var arr2 = [...arr1]; console.log(arr2); // ['a', 'b', 'c'] // For Objects const obj1 = { a: 11, b: 22 }; const obj2 = { ...obj1 }; // creates a shallow copy console.log(obj2); // { a: 11, b: 22 }
Creating a shallow copy implies that changing original array(arr1
) will have no effect on the copied array (arr2
). This is because the value of arr1 is expanded to fill the brackets of our arr2 array definition. Thus, we are setting arr2 to equal the values of arr1 not to arr1 itself.
To clarify, if you copy the array by setting the value as var arr2 = arr1;
, any changes to arr1 will be reflected in arr2.
6. Destructuring / Rest Syntax:
The Rest Parameters looks exactly like the spread operator and is actually used for destructuring
// For Arrays var [a, ...b] = [1, 2, 3]; console.log(a); // 1 console.log(b); // [2, 3] // For Objects let {a, b, ...rest} = {a: 10, b: 20, c: 30, d: 40} console.log(a); // 10 console.log(b); // 20 console.log(rest); // { c: 30, d: 40 }
As seen above, you can extract the information into variables. The remaining unassigned properties are added on to the variable with the spread operator.
7. Conditional Arguments:
The spread operator can be used to pass in conditional function parameters as follows:
let condition = true; Math.max(...condition ? [10,20,30] : []) // 30 // The above code is similar: if (condition) Math.max([10,20,30]) // 30 else Math.max(); // -Infinity
Caveats:
As far as performance is concerned, there are a few cases where the spread operator falls short. For example, check out this jsperf to compare array concatenation.
Note that the ...
operator used with Arrays is a part of ES6. But using it with Objects is a stage-3 addition. And although transpilers like babel, typescript support it, it is not the standard as yet.
All modern browsers support the new ES6 syntax so if you haven’t taken the time to play around, you definitely should. The Spread operator is a useful addition that one must be aware of!