Let's try to implement a very simple function that sums up the numbers. First, let's define the sum()
function, which takes two numbers as input and returns their sum:
const sum = (a, b) => a + b;
sum(1, 2); // 3
sum(-3, 10); // 7
So far, everything is simple and straightforward. Difficulties arise with additional requirements: what if we want to sum up not two but three numbers? Or five, or even ten? Writing a separate function to handle each case is obviously a bad idea:
const sumOfTwo = (a, b) => a + b;
const sumOfTree = (a, b, c) => a + b + c;
const sumOfTen = (a, b, c, d, e, f, g, h, i, j) => a + b + c + d + e + f + g + h + i + j; // ugh...
// const sumoOfThousand = ???
// const sumOfMillion = ???
It is necessary that a single function can work with a different number of arguments. How do you do that?
You may notice that there are functions in the standard JavaScript library that can take different numbers of arguments. For example, the signature of the Math.max() function is defined as follows:
Math.max([value1[, value2[, ...]]])
It tells us that you can pass any number of elements to Math.max()
and they are optional:
Math.max(10, 20); // 20
Math.max(10, 20, 30); // 30
Math.max(10, 20, 30, 40, 50); // 50
Math.max(-10, -20, -30); // -10
In terms of calling, nothing unusual, just a different number of arguments. But the definition of a function with a variable number of arguments looks unusual:
const func = (...params) => {
// params is an array containing all
// arguments passed in the function call
console.log(params);
};
func(); // => []
func(9); // => [9]
func(9, 4); // => [9, 4]
func(9, 4, 1); // => [9, 4, 1]
func(9, 4, 1, -3); // => [9, 4, 1, -3]
https://repl.it/@hexlet/js-functions-rest-operator-rest-parameters-en
The colon character ...
before a formal parameter name in the function definition denotes a rest operator. Writing ...params
in the func()
definition from the example above literally means the following: "place all arguments passed in the function call into the params
array".
If no arguments are passed at all, the params
array will be empty:
func(); // => []
You can pass any number of arguments to a function - all of them will go into the params
array:
func(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
// => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Arguments can be of any type - numbers, strings, arrays, etc:
func(1, 2, 'hello', [3, 4, 5], true);
// => [1, 2, 'hello', [3, 4, 5 ], true]
Now we have enough knowledge to rewrite our sum()
function using the rest operator so that it can sum any number of numbers (not just two numbers, like now):
const sum = (...numbers) => {
// The default is 0, since the sum of nothing is 0
let result = 0;
for (const num of numbers) {
result += num;
}
return result;
};
sum(); // 0
sum(10); // 10
sum(10, 4); // 14
sum(8, 10, 4); // 22
https://repl.it/@hexlet/js-functions-rest-operator-sum
In that context, an array can be thought of as "optional arguments" that you can either not pass at all or pass as many as you want. But what if we want a function to have two ordinary ("required") named parameters and the rest to be optional and stored in a rest-array? It's simple: when defining a function, we first specify the standard named formal parameters (e.g., a
and b
) and add a rest-array at the end:
const func = (a, b, ...params) => {
// the 'a' parameter contains the first argument
console.log(`a -> ${a}`);
// // the 'b' parameter contains the second argument
console.log(`b -> ${b}`);
// params contains all arguments
console.log(params);
};
func(9, 4);
// => a -> 9
// => b -> 4
// => []
func(9, 4, 1);
// => a -> 9
// => b -> 4
// => [1]
func(9, 4, 1, -3);
// => a -> 9
// => b -> 4
// => [1, -3]
func(9, 4, 1, -3, -5);
// => a -> 9
// => b -> 4
// => [1, -3, -5]
https://repl.it/@hexlet/js-functions-rest-operator-many-more-args-en
The same can be done for a single argument:
const func = (a, ...params) => {
// ...
};
and for three:
const func = (a, b, c, ...params) => {
// ...
};
This idea can go on and on, making as many arguments as required mandatory. The only restriction: the rest operator can only be used for the last parameter. That is, such code is syntactically incorrect:
const func = (...params, a) => {
// ...
};
That one, too:
const func = (a, ...params, b) => {
// ...
};
This is why the operator is called rest, that is, it organizes the storage of the "rest" ("remaining", last) parameters.
Are there any more questions? Ask them in the Discussion section.
The Hexlet support team or other students will answer you.
For full access to the course you need a professional subscription.
A professional subscription will give you full access to all Hexlet courses, projects and lifetime access to the theory of lessons learned. You can cancel your subscription at any time.