In JavaScript functions, parameters are the names in the definition; arguments (the values at call time) can be read from bindings like a and b, or from the legacy arguments object. People also say args javascript when they mean either that object or, more often today, a rest parameter like (...args). Modern style favors rest parameters and spread in calls; see the spread operator in JavaScript for ... in expressions versus parameter lists.
Tested on: Node.js v20.18.2. A short note after each snippet describes what you should see in the console.
Quick reference
Rest parameters (...args) are the modern replacement for almost every arguments use case: real arrays, clearer signatures, and no coupling to parameter renames.
| Situation | Prefer |
|---|---|
| New variadic functions | ...args (real array) |
| Need array methods on call values | Array.from(arguments) or rest |
| Sloppy simple parameters | Know arguments[i] can alias names |
| ES modules / strict | No live link; treat arguments as read-only history |
Simple parameters and the arguments object
In non-strict functions whose parameters are only simple (no defaults, rest, or destructuring), arguments[i] and the matching parameter can stay linked until the binding is broken in spec-defined ways:
function test(a, b, c) {
console.log("first:", a, arguments[0]);
console.log("second:", b, arguments[1]);
console.log("third:", c, arguments[2]);
}
test("fun", "js", "secrets");You should see 3 lines: first: fun fun, then second: js js, then third: secrets secrets.
Reassigning a parameter or an arguments index updates the paired slot:
function test(a, b, c) {
a = "nice";
arguments[1] = "JavaScript";
console.log("first:", a, arguments[0]);
console.log("second:", b, arguments[1]);
console.log("third:", c, arguments[2]);
}
test("fun", "js", "secrets");You should see 3 lines: first: nice nice, then second: JavaScript JavaScript, then third: secrets secrets.
Strict mode: no live link
With "use strict", arguments holds the original passed values; mutating arguments[i] does not change the parameter (and the other way around):
function strict(a) {
"use strict";
arguments[0] = 99;
return a;
}
function sloppy(a) {
arguments[0] = 99;
return a;
}
console.log("strict", strict(1), "sloppy", sloppy(1));You should see one line like: strict 1 sloppy 99.
ES modules are strict by default, so new javascript arguments code in import/export files follows the strict behavior.
Default parameters: arguments does not mirror defaults the same way
function f(a = 1) {
a = 2;
return arguments[0];
}
console.log("no arg", f());
console.log("with 10", f(10));You should see 2 lines: no arg undefined, then with 10 10.
With default parameters (and similarly with rest or destructuring parameters), treat arguments as legacy; use named parameters or ...rest instead of relying on index coupling.
Variadic sum with arguments
function sum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
console.log(sum(1, 2, 3, 4, 5));You should see one line like: 15.
Turn javascript arguments into a real array when you need array methods:
function collect() {
return Array.from(arguments);
}
console.log(collect(1, 2, 3));You should see one line like: [ 1, 2, 3 ].
Default parameter values (separate from arguments)
function hello(name = "user") {
console.log(`Hello, ${name}!`);
}
hello();
hello("David");You should see 2 lines: Hello, user!, then Hello, David!.
Rest parameters (preferred “args” today)
function sum(...numbers) {
let total = 0;
for (let i = 0; i < numbers.length; i++) {
total += numbers[i];
}
return total;
}
console.log(sum(...[1, 2, 3, 4, 5]));You should see one line like: 15.
Spread in a call: Math.max and arrays
Math.max expects separate numeric arguments, not one array value:
const numbers = [1, 7, 2, 9];
console.log(Math.max(numbers));
console.log(Math.max(...numbers));You should see 2 lines: NaN, then 9.
... token in Math.max(...numbers) is spread (expand values into the call). In function f(...values), it is a rest parameter (collect remaining arguments into an array). Same syntax, opposite direction.
Arrow functions and arguments
Arrow functions do not define their own arguments binding. They inherit arguments from the nearest enclosing non-arrow function:
function outer() {
const inner = () => arguments[0];
return inner();
}
console.log(outer("fromOuter"));You should see one line like: fromOuter.
For an arrow that stands alone, use (...args) => instead of arguments.
Summary
Treat arguments as legacy: it is array-like, not an Array, and its interaction with strict mode and non-simple parameters trips readers—default to ...args in new code.
- Parameters are declared names;
argumentsis a positional snapshot (array-like, notArray). - Strict mode and non-simple parameter lists break the old live aliasing story—prefer rest parameters.
- Use spread when calling variadic APIs like
Math.max; use rest when collecting caller inputs. - Arrows do not get their own
arguments; use an explicit...argsparameter.
References
MDN guides for the legacy object, rest parameters, spread, and strict-mode rules.
- MDN: The
argumentsobject - MDN: Rest parameters
- MDN: Spread syntax (
...) - MDN: Strict mode (
arguments) - MDN: Functions guide
