Parameters & Arguments

Parameters are the names in a function's definition; arguments are the actual values passed when it's called. JavaScript is very relaxed about matching them up, and offers default values, rest parameters and destructuring to make function inputs flexible and clear.

Missing and extra arguments

JavaScript doesn't check the number of arguments. Missing ones are undefined; extra ones are ignored:

JS count.js
function describe(name, age) {
  return `${name} is ${age}`;
}

console.log(describe("Ana", 30));
console.log(describe("Ben"));
console.log(describe("Cleo", 25, "extra"));
Output
Ana is 30
Ben is undefined
Cleo is 25

Default parameters

A default value is used when an argument is missing or explicitly undefined:

JS defaults.js
function greet(name = "friend", greeting = "Hello") {
  return `${greeting}, ${name}!`;
}

console.log(greet());
console.log(greet("Ida"));
console.log(greet("Ida", "Hey"));
console.log(greet(undefined, "Welcome"));
console.log(greet(null));
Output
Hello, friend!
Hello, Ida!
Hey, Ida!
Welcome, friend!
Hello, null!

Note the last line: null is a real value, so the default isn't used. Defaults can be expressions and can even refer to earlier parameters: function box(w, h = w).

Rest parameters

A parameter starting with ... collects all remaining arguments into a real array:

JS rest.js
function sum(...numbers) {
  return numbers.reduce((total, n) => total + n, 0);
}

function tag(label, ...items) {
  return `${label}: ${items.join(", ")}`;
}

console.log(sum(1, 2, 3, 4));
console.log(sum());
console.log(tag("Fruit", "apple", "fig", "kiwi"));
Output
10
0
Fruit: apple, fig, kiwi

The rest parameter must be last. The related spread syntax does the opposite, expanding an array into separate arguments: Math.max(...[3, 9, 2]).

The old arguments object

Regular (non-arrow) functions also have a built-in arguments object holding every argument. It's array-like but not a real array, and arrow functions don't have it. You'll see it in older code; rest parameters have replaced it.

JS arguments.js
function oldStyle() {
  return arguments.length;
}
console.log(oldStyle("a", "b", "c"));
Output
3

Options objects

Calls with many positional arguments are hard to read — what does createUser("Ana", true, false, 3) mean? Passing a single object with named properties, and destructuring it in the parameter list, solves this:

JS options.js
function createUser({ name, isAdmin = false, notify = true, retries = 3 } = {}) {
  return `${name}: admin=${isAdmin}, notify=${notify}, retries=${retries}`;
}

console.log(createUser({ name: "Ana", isAdmin: true }));
console.log(createUser({ name: "Ben", retries: 5 }));
Output
Ana: admin=true, notify=true, retries=3
Ben: admin=false, notify=true, retries=5

Each option has its own default, callers can pass options in any order, and the call site documents itself. The = {} at the end lets the function be called with no argument at all. Destructuring is covered fully in lesson 33.

Arguments are passed by value — but objects are shared

Reassigning a parameter inside a function never affects the caller's variable. But if the argument is an object, the function receives a reference to the same object, so changing its contents is visible outside:

JS by-value.js
function tryToReplace(n, list) {
  n = 100;
  list = ["replaced"];
}

function addItem(list) {
  list.push("added");
}

let count = 1;
const items = ["original"];

tryToReplace(count, items);
console.log(count, items);

addItem(items);
console.log(items);
Output
1 [ 'original' ]
[ 'original', 'added' ]

Functions that change their arguments' contents can cause surprising bugs. Where practical, return a new array or object instead: return [...list, "added"].

Try it yourself

Try it yourself
Console output