JavaScript REST Parameters: A Complete Tutorial

Rest parameters collect extra function arguments into a real array. Learn how ...args replaces the arguments object with cleaner, more predictable code.

6 min read

Rest parameters let a function accept any number of arguments by collecting the extras into a real array. The syntax is three dots before the last parameter name: ...args.

javascriptjavascript
function sum(...numbers) {
  return numbers.reduce((total, n) => total + n, 0);
}
 
console.log(sum(1, 2, 3));       // 6
console.log(sum(10, 20, 30, 40)); // 100

No matter how many arguments you pass, they all land in the numbers array. The function handles one or one hundred arguments the same way, with no need to check how many were actually passed.

Rest Parameters vs the arguments Object

Before rest parameters, the arguments object was the only way to handle a variable number of arguments inside a function body. It works, but it comes with several rough edges that rest parameters were specifically designed to fix:

Rest Parametersarguments Object
TypeReal ArrayArray-like object
Array methodsDirectly usableMust convert first
Arrow functionsWorksNot available
Named parametersExcluded from restIncludes everything
Default valuesNot on rest paramN/A

The biggest practical advantage: rest parameters are real arrays. You can call map, filter, reduce, sort, or any array method directly, with no conversion step in between:

javascriptjavascript
// With arguments (requires conversion)
function sortOld() {
  const args = Array.from(arguments);
  return args.sort();
}
 
// With rest parameters (no conversion needed)
function sortNew(...items) {
  return items.sort();
}
 
console.log(sortNew(3, 1, 4, 1, 5)); // [1, 1, 3, 4, 5]

Syntax Rules

Rest parameters have strict placement rules. Both valid forms below work because the rest parameter is always the last one in the list:

javascriptjavascript
// Valid: rest parameter as the only parameter
function logAll(...items) {
  console.log(items);
}
 
// Valid: named parameters first, then rest
function greet(greeting, ...names) {
  console.log(`${greeting}, ${names.join(" and ")}!`);
}

Each of the following breaks one of those rules, and each one on its own is a SyntaxError that stops the file from parsing:

javascriptjavascript
// SyntaxError: rest parameter must be last
function wrong(...items, last) {}
 
// SyntaxError: only one rest parameter allowed
function wrong2(...a, ...b) {}
 
// SyntaxError: rest parameter cannot have a default
function wrong3(...items = [1, 2]) {}

The rules are simple: exactly one rest parameter, always at the end, no default value.

Rest Parameters Always Produce an Array

Even when no extra arguments are passed, the rest parameter is an empty array, never undefined:

javascriptjavascript
function show(a, b, ...rest) {
  console.log("a:", a);
  console.log("b:", b);
  console.log("rest:", rest);
}
 
show(1, 2);        // a: 1, b: 2, rest: []
show(1, 2, 3, 4);  // a: 1, b: 2, rest: [3, 4]
show(1);           // a: 1, b: undefined, rest: []

This consistency means you can safely call array methods on the rest parameter without null checks. There is no need to write a guard clause checking whether the rest parameter exists before calling map or filter on it, since JavaScript guarantees an array every time.

Rest Parameters and function.length

Rest parameters do not contribute to the function's length property:

javascriptjavascript
function f1(a, b) {}          // f1.length === 2
function f2(a, b, ...rest) {} // f2.length === 2
function f3(...rest) {}       // f3.length === 0

The length property counts only the parameters before the first rest parameter, and before the first default parameter as well. Libraries that inspect a callback's length to decide how to call it need to be aware of this, since a rest parameter effectively hides itself from that count.

Practical Use Cases

Rest parameters show up naturally whenever a function needs to accept an open-ended list of values rather than a fixed set of named ones.

Sum or Combine Any Number of Values

javascriptjavascript
function average(...numbers) {
  const total = numbers.reduce((sum, n) => sum + n, 0);
  return total / numbers.length;
}
 
console.log(average(10, 20, 30)); // 20

This function accepts any number of numbers and averages them, since the reduce call and the length property both work directly on the rest array without any extra conversion step.

Collect Extra Arguments After Named Ones

Rest parameters do not have to be the only parameter. A function can take one or more named arguments first, then collect everything else into the rest parameter:

javascriptjavascript
function formatList(separator, ...items) {
  return items.join(separator);
}
 
console.log(formatList(" | ", "a", "b", "c")); // "a | b | c"

The first argument is separator. Everything else goes into items, no matter how many values are passed after it.

Wrap Another Function

javascriptjavascript
function logCalls(fn, ...args) {
  console.log(`Calling with args:`, args);
  return fn(...args);
}
 
function add(a, b) {
  return a + b;
}
 
console.log(logCalls(add, 3, 4));
// Calling with args: [3, 4]
// 7

Rest parameters collect the arguments. The spread operator, the same three-dot syntax used in a different position, then passes them back out into the wrapped function individually, so calling the function this way runs it exactly as if you had listed each argument by hand.

Destructuring with Rest

Rest parameters can also combine with array destructuring, which lets you skip specific positions in the collected arguments rather than keeping the whole list:

javascriptjavascript
function ignoreFirstAndSecond(...[, , third, ...rest]) {
  return { third, rest };
}
 
console.log(ignoreFirstAndSecond("a", "b", "c", "d", "e"));
// { third: "c", rest: ["d", "e"] }

Rest Parameters in Arrow Functions

Since arrow functions do not have the arguments object, rest parameters are the only way to handle variable arguments:

javascriptjavascript
const multiply = (multiplier, ...numbers) => {
  return numbers.map(n => n * multiplier);
};
 
console.log(multiply(2, 1, 2, 3)); // [2, 4, 6]

This is the recommended modern pattern. Even in regular functions, prefer rest parameters over arguments for cleaner, more predictable code.

For more on how parameters and arguments work, see JS Function Parameters vs Arguments Differences. For default values in parameters, see How to Use Default Parameters in JS Functions.

Rune AI

Rune AI

Key Insights

  • Rest parameters (...args) collect extra arguments into a real JavaScript array.
  • Unlike arguments, rest parameters are true arrays with map, filter, reduce, and other methods.
  • Only one rest parameter is allowed per function, and it must be the last parameter.
  • Rest parameters work in arrow functions, making them the modern replacement for arguments.
  • If no extra arguments are passed, the rest parameter is an empty array, never undefined.
RunePowered by Rune AI

Frequently Asked Questions

What is the difference between rest parameters and the spread operator?

They use the same ... syntax but in opposite contexts. Rest parameters collect values into an array in function definitions. The spread operator expands an array into individual values in function calls or array literals.

Can I have more than one rest parameter?

No. A function can have only one rest parameter, and it must be the last parameter in the list.

Do rest parameters work in arrow functions?

Yes. Rest parameters are the recommended way to handle variable arguments in arrow functions since arrow functions do not have the arguments object.

Conclusion

Rest parameters replace the arguments object with a real array, cleaner code, and predictable behavior. Use ...args to collect extra arguments in modern JavaScript. Just remember the rules: only one rest parameter, it must come last, and it always produces an array -- even when empty.