The Spread Operator

The spread operator looks the same as the symbol (...) used for the rest parameter, but it appears on the calling side of functions instead of on the parameter or receiving side. The intention of the spread operator is the opposite of that of the rest parameter—spread breaks a collection into discrete values whereas rest gathers discrete values into an array. Since they are used in two different contexts, there should be no confusion.

Suppose we have a greet() function that takes a rest parameter, like so:

 const​ greet = ​function​(...names) {
  console.log(​'hello '​ + names.join(​', '​));
 };

If we have discrete variables, we can readily send them to the greet() function:

 const​ jack = ​'Jack'​;
 const​ jill = ​'Jill'​;
 greet(jack, jill);

If we had the names in an array, then we could pass them to the function after indexing into the array:

 const​ tj = [​'Tom'​, ​'Jerry'​];
 greet(tj[0], tj[1]);

But that’s boring—there’s gotta be a better way. Enter the spread operator.

 greet(...tj);

The spread operator may be used with any iterable object, and it expands, or spreads, the contained values into discrete values.

The spread operator retires the apply() function that is available in JavaScript—there’s no more reason to use that function:

 greet.apply(​null​, tj); ​//no more stinky null

While spread may appear to be a direct replacement for the apply() function, we actually can get more mileage out of spread than when using apply().

The power and versatility of the spread operator is impressive. The spread operator isn’t limited to the calling side of the rest parameter, like in the call to the greet() function. It may be used to spread an array to discrete parameters too, even when no rest parameter is involved. For example, in the next piece of code the function doesn’t use a rest parameter but the caller uses a spread operator.

 const​ names1 = [​'Laurel'​, ​'Hardy'​, ​'Todd'​];
 const​ names2 = [​'Rock'​];
 
 const​ sayHello = ​function​(name1, name2) {
  console.log(​'hello '​ + name1 + ​' and '​ + name2);
 };
 
 sayHello(...names1);
 sayHello(...names2);

The function sayHello() takes two separate named parameters. We can use a spread operator to invoke this function. If we pass an array with more values than necessary, the extras are ignored. If we are shy, then the parameter becomes undefined. We can see this from the output:

 hello Laurel and Hardy
 hello Rock and undefined

We can also mix the spread operator with other discrete arguments and also when the receiver has a mixture of named parameters and the rest parameter. Here’s an example to illustrate:

 const​ mixed = ​function​(name1, name2, ...names) {
  console.log(​'name1: '​ + name1);
  console.log(​'name2: '​ + name2);
  console.log(​'names: '​ + names);
 };
 
 mixed(​'Tom'​, ...[​'Jerry'​, ​'Tyke'​, ​'Spike'​]);

The function has two named parameters and one rest parameter. The caller is passing a separate stand-alone value ’Tom’ followed by a spread argument. The stand-alone argument binds to the first parameter, name1; the first value within the spread argument binds to the second named argument, name2; and the rest of the values in the spread argument go to the rest parameter.

 name1: Tom
 name2: Jerry
 names: Tyke,Spike

The now out-of-favor apply() function was only useful to expand values in a iterable when used in a function call. It could not be used with constructors. The spread operator works with constructors too:

 const​ patternAndFlags = [​'r'​, ​'i'​];
 
 const​ regExp = ​new​ RegExp(...patternAndFlags);

The spread operator can also be used to copy, concatenate, and manipulate arrays:

 const​ names1 = [​'Tom'​, ​'Jerry'​];
 const​ names2 = [​'Butch'​, ​'Spike'​, ​'Tyke'​];
 
 console.log([...names1, ​'Brooke'​]);
 console.log([...names1, ...names2]);
 console.log([...names2, ​'Meathead'​, ...names1]);

The argument passed to the first log() call creates a new array with all of the values from the array names1 and an additional value as the last element. The argument passed to the second log creates a new array by concatenating arrays names1 and names2. The last one creates a new array with all of the elements from names2 followed by one arbitrary new element, then again followed by all of the elements from the names1 array. The output reflects the action of the code:

 [ 'Tom', 'Jerry', 'Brooke' ]
 [ 'Tom', 'Jerry', 'Butch', 'Spike', 'Tyke' ]
 [ 'Butch', 'Spike', 'Tyke', 'Meathead', 'Tom', 'Jerry' ]

The spread operator has yet another charming capability. It may be used to copy contents of an object while optionally providing new values for some field and/or adding new fields. This is a feature used quite extensively in the popular JavaScript state container library Redux,[14] for example, to conveniently make copies of immutable state. To see this excellent use of the spread operator, let’s make copies of an object in the next example.

 const​ sam = { name: ​'Sam'​, age: 2 };
 
 console.log(sam);
 console.log({...sam, age: 3});
 console.log({...sam, age: 4, height: 100 });
 console.log(sam);

We first print the original object created on the first line. Then we make a copy of the object while replacing the age field with a new value of 3. Then, we make another copy, this time replacing age with the value 4 while inserting a new height field. The last line outputs the original object to confirm it has not changed. Here’s the output:

 { name: 'Sam', age: 2 }
 { name: 'Sam', age: 3 }
 { name: 'Sam', age: 4, height: 100 }
 { name: 'Sam', age: 2 }

Beyond looking elegant and concise, the spread operator when used in this context makes the code highly extensible. If later on we add more properties to the object, the copy automatically takes care of copying over the extra properties without us having to modify the code. That can eliminate quite a few errors and makes the code easier to maintain.

Next, we will visit another excellent addition to the language, the default parameters.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset