Skip to content
academia.sh

Lesson 14 / 21

Parameters

Missing and extra arguments, the condition under which default values kick in, rest parameters and spread, the arguments object, and destructured parameters.

Contents

In the previous lesson, functions were called with a fixed number of arguments. JavaScript is loose about this: a missing argument throws no error, and neither does an extra one. The cost of this looseness is that a missing argument stays silent.

This lesson covers parameter rules. The Programming Fundamentals course’s Value and Reference, and Passing lesson established the parameter–argument distinction and the concept of a variable number of arguments; here, which syntax JavaScript meets these concepts with, and which traps it carries, are shown.

Missing and Extra Arguments

A parameter not given at the call site gets the value undefined. An extra argument given is silently ignored:

function report(station, threshold) {
  return `${station} / ${threshold}`;
}
console.log(report("A1"));
console.log(report("A1", 20, "extra"));
A1 / undefined
A1 / 20

Neither behavior produced an error. This is a deliberate decision of the language and makes it possible for functions to behave differently based on argument count. Its cost is that an argument left missing by a typo is only noticed once it carries an undefined value into a later operation and breaks it.

Default Values

A parameter can be given a default value. The default kicks in only when the argument is undefined — whether it is missing or explicitly given as undefined.

function report(station, threshold = 20) {
  return `${station} / ${threshold}`;
}
console.log(report("A1"));
console.log(report("A1", undefined));
console.log(report("A1", null));
console.log(report("A1", 0));
console.log(report.length);
A1 / 20
A1 / 20
A1 / null
A1 / 0
1

The third and fourth lines show that this is a narrower criterion than even the ?? operator from the Truthiness lesson: not even null triggers the default. The value 0 also passes through — default values naturally avoid the trap that a fallback assignment written with || would fall into.

The last line shows that the length property gives the parameter count before the parameter with a default.

Default expressions are re-evaluated on every call and can use the parameters that come before them:

let counter = 0;
function next() {
  counter += 1;
  return counter;
}
function label(name, sequence = next()) {
  return `${name}-${sequence}`;
}
console.log(label("A1"));
console.log(label("A2"));
console.log(label("B1", 99));
console.log(label("B2"));
A1-1
A2-2
B1-99
B2-3

In the third call, next was never called because an argument was given; the counter did not increase. This is proof that a default is evaluated at call time and only when needed.

A default resting on a previous parameter is useful in range definitions:

function range(low, high = low + 5) {
  return [low, high];
}
console.log(range(18));
console.log(range(18, 30));
[ 18, 23 ]
[ 18, 30 ]

The order is one-directional: a parameter can refer only to parameters written before it.

A default expression being evaluated at call time also opens a way to declare required parameters:

function required(name) {
  throw new Error(`${name} parameter is required`);
}
function save(station = required("station"), temperature = required("temperature")) {
  return `${station}=${temperature}`;
}
console.log(save("A1", 21.5));
try {
  save("A1");
} catch (error) {
  console.log(error.name + ": " + error.message);
}
A1=21.5
Error: temperature parameter is required

When an argument is given, the default expression never runs; when it is not given, an error is thrown. Error objects and the throw statement are covered in this topic’s last lesson.

Rest Parameters and Spread

Arguments whose count is not known in advance are collected with a rest parameter. The three-dot spelling puts all remaining arguments into a real array:

function highest(label, ...readings) {
  return `${label}: ${Math.max(...readings)} (${readings.length} readings)`;
}
console.log(highest("A1", 21.5, 19.75, 23));
console.log(highest("B1"));
console.log(highest.length);
A1: 23 (3 readings)
B1: -Infinity (0 readings)
1

The second line shows an edge case: called with no readings, readings is an empty array, and Math.max() gives -Infinity. This is mathematically consistent — the maximum of an empty set returns the neutral element — but is meaningless in a measurement context. An empty-list check should be written.

The same three dots work in the opposite direction at the call site: they spread an array into separate arguments.

function highest(label, ...readings) {
  return `${label}: ${Math.max(...readings)}`;
}
const temperatures = [21.5, 19.75, 23, 18.25];
console.log(highest("all", ...temperatures));
all: 23

The two uses should not be confused. Three dots in a parameter list collect; three dots at a call site spread. The same syntax’s two directions are told apart by where they sit.

A rest parameter can only be in the last position and is not counted toward the length property.

The Arguments Object

Before rest parameters, a variable number of arguments was read through an implicit object called arguments. This object still exists and is found in older code:

function oldForm() {
  console.log(typeof arguments, arguments.length);
  console.log(Array.isArray(arguments));
  console.log(Array.from(arguments));
}
oldForm(21.5, 19.75);
object 2
false
[ 21.5, 19.75 ]

The second line is the problem itself: arguments is not an array. It has a length and indices, but no array methods; it has to be converted to an array first to be used.

A second problem shows up with default values:

function withDefault(a = 1) {
  console.log("arguments.length:", arguments.length, "a:", a);
}
withDefault();
withDefault(5);
arguments.length: 0 a: 1
arguments.length: 1 a: 5

arguments only counts the arguments actually given; it does not see a parameter filled in by a default. The two sources of information diverge, and which one to read becomes unclear.

Third, arguments is not found at all in arrow functions — this topic’s next subject. In this course, a variable number of arguments will always be written with a rest parameter.

Destructured Parameters

In a function taking more than three or four parameters, the call line becomes unreadable: the order has to be memorized. The solution is to gather the options into an object and unpack it in the parameter list through destructuring:

function summarize({ station, temperature, unit = "C" }) {
  return `${station}: ${temperature} ${unit}`;
}
console.log(summarize({ station: "A1", temperature: 21.5 }));
console.log(summarize({ station: "A2", temperature: 19.75, unit: "K" }));
A1: 21.5 C
A2: 19.75 K

The call line now states which value is which on its own, and order no longer matters. Defaults can be given to individual fields one by one.

This spelling has a trap: if the argument is not given at all, destructuring tries to operate on undefined:

function summarize({ station, temperature }) {
  return `${station}: ${temperature}`;
}
try {
  console.log(summarize());
} catch (error) {
  console.log(error.name + ": " + error.message);
}
TypeError: Cannot destructure property 'station' of 'undefined' as it is undefined.

The fix is to give the entire parameter an empty-object default:

function summarizeSafe({ station = "?", temperature = null } = {}) {
  return `${station}: ${temperature}`;
}
console.log(summarizeSafe());
console.log(summarizeSafe({ station: "B1" }));
?: null
B1: null

Two layers of defaults work together: the outer = {} kicks in if the object itself is missing, the inner ones kick in if individual fields are missing.

If all of a function’s options are required, the outer default is not written; then a missing call throws an error, and this is the intended behavior. The choice depends on what the contract is.

Summary

  • A missing argument becomes undefined, an extra argument is ignored; neither produces an error.
  • A default value kicks in only when the argument is undefined; null and 0 do not trigger the default.
  • Default expressions are evaluated on every call and only when needed; they can use the parameters before them.
  • A rest parameter collects arguments into a real array and must be last; three dots at a call site work in reverse, spreading an array into arguments.
  • The arguments object is not an array and does not count parameters filled by a default; this course uses rest parameters.
  • A destructured parameter provides named options; if the whole object has no default, a call with no arguments throws an error.

Next Step

Short forms like (d) => d > threshold were used unexplained in this lesson. The next lesson covers arrow functions: the forms of the short syntax, the implicit return rule, and the difference these functions have from the arguments object and from context behavior. The difference is not just brevity — an arrow function cannot be used in some places.

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ Esc navigate · open · close