A rest
parameter will collect individual parameters into an array when you use the dots in a function parameter definition, while the spread operator expands an array into individual parameters when using the dots in a function call
.
When ever you want to collect individual parameters into an array, you would use rest
operator in your function param definition.
let sum = (...numbers) => {
let result = 0;
numbers.forEach(function(n){
result += n;
});
return result;
};
console.log(sum(1,2,3));
Dealing with arguments
object inside nested function becomes really tricky, let's visit the below situation where our inner function needs access to the arguments
object passed.
If our inner function filterNumbers
needs access to arguments, it has to be stored above in a variable
before passing it further as each function has its own arguments
object, which is an array like object.
function sumOnlyNumbers() {
var args = arguments;
var numbers = filterNumbers();
return numbers.reduce((sum, element) => sum + element);
function filterNumbers() {
return Array.prototype.filter.call(args,
element => typeof element === 'number'
);
}
}
sumOnlyNumbers(1, 'Hello', 5, false);
The approach works, but it's too verbose. var args = arguments
can be omitted and Array.prototype.filter.call(args)
can be transformed to args.filter()
using a rest
parameter.
function sumOnlyNumbers(...args) {
var numbers = filterNumbers();
return numbers.reduce((sum, element) => sum + element);
function filterNumbers() {
return args.filter(element => typeof element === 'number');
}
}
sumOnlyNumbers(1, 'Hello', 5, false); // => 6
When ever you want to expand an array into individual parameters, you would use spread operator in your function call.
let sum = (a,b,c) => {
return a + b + c;
};
console.log(sum(...[1,2,3]));
In the above code, the spread operator will “spread”
the array of three values across the parameters a, b, and c
. The spread
operator can also expand an array to create individual elements in an array
literal.
var a = [4, 5, 6];
var b = [1, 2, 3, ...a, 7, 8, 9]
console.log(b);
Improved function invocation in ES6
ES5
provides .apply()
method on the function object to solve this. Unfortunately this technique has 3 problems:
- It's necessary to indicate manually the context of the function
invocation
- Is not possible to use in a constructor invocation
- A shorter solution is more preferable
It seems irrelevant to indicate in .apply()
second time the context countries making it more verbose.
let countries = ['India', 'USA'];
let otherCountries = ['China', 'Japan'];
countries.push.apply(countries, otherCountries);
console.log(countries); // => ['India', 'USA', 'China', 'Japan']
The spread
operator fills the function
invocation arguments with values from an array
. Let's improve the above sample with a spread operator:
let countries = ['India', 'USA'];
let otherCountries = ['China', 'Japan'];
countries.push(...otherCountries);
console.log(countries); // => ['Moldova', 'Ukraine', 'USA', 'Japan']
Spread
operator configures the constructor invocation arguments from an array, which is bit complicated and difficult directly when using .apply()
.
class Actor {
constructor(name, country) {
this.name = name;
this.country = country;
}
getDescription() {
return `${this.name} leads ${this.country}`;
}
}
var details = ['RajiniKanth the Great', 'India'];
var Alexander = new Actor(...details);
console.log(Alexander.getDescription()); // => 'RajiniKanth the Great leads India'
Moreover you can combine multiple spread
operators and regular arguments in the same invocation. The following example is removing from an array existing elements, then adds other array and an element:
var numbers = [1, 2];
var evenNumbers = [4, 8];
const zero = 0;
numbers.splice(0, 2, ...evenNumbers, zero);
console.log(numbers); // => [4, 8, 0]
Clone an array instance:
var words = ['Hi', 'Hello', 'Good day'];
var otherWords = [...words];
console.log(otherWords); // => ['Hi', 'Hello', 'Good day']
console.log(otherWords === words); // => false
otherWords
is a clone version of words array. Notice that cloning happens only on array itself, but not on the contained elements (i.e. it's not a deep clone).
References: https://dmitripavlutin.com/how-three-dots-changed-javascript/
...
is not an operator after all. – Transilient