Skip to content
aviral gupta

// B4.2 · ~30 min · Beginner

Default and rest parameters

After this lesson you know what a parameter holds when its argument is missing, give it a default value, and collect any number of arguments into an array.

Lesson 2 of 5 in B4 Functions

You will be able to

  • Predict what a parameter holds when its argument is missing, and give it a default value
  • Know which arguments use the default: a missing one or undefined, but not null, 0 or ""
  • Collect any number of arguments into a real array with a rest parameter, ...items
  1. Warm-up · Activity 1 of 7

    Warm-up: a function is declared as function f(a, b). It is called as f(1). What does b hold inside the call?

  2. Predict · Activity 2 of 7

    Predict before you read on: what does this print?

    function greet(name = "friend") {
      return "Hello, " + name;
    }
    console.log(greet(), "|", greet(null));
  3. Practice · Activity 3 of 7

    Give factor a default of 2, so that scale(5) gives 10 and scale(5, 3) gives 15.

    function scale(value, factor____) {
      return value * factor;
    }
    console.log(scale(5), scale(5, 3));
    function scale(value, factor) {
  4. Practice · Activity 4 of 7

    function show(a = "default") { return a; }. Match each call to what console.log prints for it.

  5. Practice · Activity 5 of 7

    What does this print?

    function count(first, ...others) {
      return others.length;
    }
    console.log(count("a", "b", "c", "d"));
  6. Brain teaser · Activity 6 of 7

    Brain teaser. total adds up its arguments. It is called once with an array and once with the array spread out. What does this print?

    function total(...prices) {
      let sum = 0;
      for (const p of prices) {
        sum += p;
      }
      return sum;
    }
    const basket = [4, 6, 10];
    console.log(total(basket), total(...basket));
  7. Apply · Activity 7 of 7

    Mini-task. Write receipt(customer, ...prices) with a default of "guest" for customer. It adds up the prices and returns a line such as Ada paid 12.5 EUR for 3 item(s). Call it with a name and three prices, with undefined and one price, and with a name and no prices at all.

    Check your work against this list

Build it yourself

Read the worked example, then write the exercises. Your code runs in your browser or on your computer and is never uploaded.

Worked example

A pizza order line

orderLine takes a pizza, a size with the default "medium", and any number of toppings in a rest parameter. Watch the four calls: one leaves the size out, one passes it, one passes undefined to keep the default while adding toppings, and one passes null. The last line shows that a rest parameter is an array, even an empty one. Run it, then add a fifth call of your own.

main.js

// A pizza order line: a default size and any number of toppings.
function orderLine(pizza, size = "medium", ...toppings) {
  let line = size + " " + pizza;
  for (const t of toppings) {
    line += " + " + t;
  }
  return line;
}

function toppingsOf(...toppings) {
  return toppings;
}

console.log(orderLine("margherita"));
console.log(orderLine("margherita", "large"));
console.log(orderLine("funghi", undefined, "olives", "chili"));
console.log(orderLine("funghi", null));
console.log(toppingsOf("ham", "basil"), toppingsOf().length);

Run it with

node main.js

Output

medium margherita
large margherita
medium funghi + olives + chili
null funghi
[ 'ham', 'basil' ] 0
  • A missing size and an undefined size both give the default, medium.
  • null is a value, so the default is not used and the line starts with null.
  • toppings is an array: with no toppings it is empty, and the for...of loop does not run.
  • toppingsOf() with no arguments returns an empty array, whose length is 0.
Change it and run it

Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.

The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.

Exercises

Exercise 1 of 2

A greeting with defaults

greet(name, greeting) should return a line such as Hi, Ada!. Give name the default "guest" and greeting the default "Hello", so that greet() returns Hello, guest! and greet(undefined, "Hey") returns Hey, guest!. Use defaults in the parameter list, not an if in the body.

Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.

The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.

Hints
  1. Hint 1

    Run the tests: greet() returns undefined, undefined!, because both parameters are missing.

  2. Hint 2

    A default goes right after the parameter name: name = "guest".

  3. Hint 3

    Write both: function greet(name = "guest", greeting = "Hello").

Show a solution

One way to solve it. Yours can look different and still pass the checks.

export function greet(name = "guest", greeting = "Hello") {
  return greeting + ", " + name + "!";
}
Run it on your computer

Install ECMAScript 2026 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.

main.js

export function greet(name, greeting) {
  return greeting + ", " + name + "!";
}

main.test.js

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {greet} from './main.js';

test('greet() uses both defaults', () => {
  assert.equal(greet(), 'Hello, guest!', `greet() returned ${JSON.stringify(greet())}, expected "Hello, guest!"`);
});

test('greet("Ada") keeps the default greeting', () => {
  assert.equal(greet('Ada'), 'Hello, Ada!', `greet("Ada") returned ${JSON.stringify(greet('Ada'))}, expected "Hello, Ada!"`);
});

test('greet("Ada", "Hi") uses both arguments', () => {
  assert.equal(greet('Ada', 'Hi'), 'Hi, Ada!', `greet("Ada", "Hi") returned ${JSON.stringify(greet('Ada', 'Hi'))}, expected "Hi, Ada!"`);
});

test('undefined as the name gives the default', () => {
  assert.equal(greet(undefined, 'Hey'), 'Hey, guest!', `greet(undefined, "Hey") returned ${JSON.stringify(greet(undefined, 'Hey'))}, expected "Hey, guest!"`);
});

package.json

{
  "type": "module"
}

package.json tells Node.js that the .js files are modules; keep it in the folder.

Run the program:

node main.js

Run the checks (needs learnrun.js in the same folder):

node --test
Download learnrun.js

Exercise 2 of 2

The average of any count

average should take any number of numbers as separate arguments, average(2, 4, 6), and return their average: 4. With no arguments at all it returns 0 instead of dividing by zero. The starter expects a single array and fails. Change the parameter into a rest parameter and handle the empty case.

Tab indents and Shift+Tab outdents. To leave the editor with the keyboard, press Esc, then Tab.

The first run downloads the JavaScript runner (up to 0.1 MB) and keeps it cached. Your code runs in your browser’s own engine and stays on your device.

Hints
  1. Hint 1

    Run the tests: average(2, 4, 6) passes three arguments, but numbers receives only the 2. A for...of loop over a number fails.

  2. Hint 2

    Put three dots in front of the parameter: ...numbers collects every argument into an array.

  3. Hint 3

    With no arguments, numbers is an empty array and sum / 0 is NaN. Return numbers.length === 0 ? 0 : sum / numbers.length.

Show a solution

One way to solve it. Yours can look different and still pass the checks.

export function average(...numbers) {
  let sum = 0;
  for (const n of numbers) {
    sum += n;
  }
  return numbers.length === 0 ? 0 : sum / numbers.length;
}
Run it on your computer

Install ECMAScript 2026 or newer. Save these files in one folder, open a terminal in that folder, and run the commands below.

main.js

export function average(numbers) {
  let sum = 0;
  for (const n of numbers) {
    sum += n;
  }
  return sum / numbers.length;
}

main.test.js

import {test} from 'node:test';
import assert from 'node:assert/strict';
import {average} from './main.js';

test('average(2, 4, 6) is 4', () => {
  assert.equal(average(2, 4, 6), 4, `average(2, 4, 6) returned ${average(2, 4, 6)}, expected 4`);
});

test('works with two numbers', () => {
  assert.equal(average(1, 2), 1.5, `average(1, 2) returned ${average(1, 2)}, expected 1.5`);
});

test('works with one number', () => {
  assert.equal(average(5), 5, `average(5) returned ${average(5)}, expected 5`);
});

test('average() with no numbers is 0', () => {
  assert.equal(average(), 0, `average() returned ${average()}, expected 0`);
});

package.json

{
  "type": "module"
}

package.json tells Node.js that the .js files are modules; keep it in the folder.

Run the program:

node main.js

Run the checks (needs learnrun.js in the same folder):

node --test
Download learnrun.js

Common mistakes

Forgetting an argument

function shout(text) {
  return text.toUpperCase() + "!";
}
console.log(shout());

What Node.js prints

TypeError: Cannot read properties of undefined (reading 'toUpperCase')

Why, and the fix

shout() passes no argument, so text is undefined, and undefined has no methods. The message names the method that was looked up on undefined. Pass the argument, shout("hi"), or give the parameter a default: function shout(text = "") { … }.

Expecting null to use the default

function greet(name = "guest") {
  return "Hello, " + name.toUpperCase();
}
console.log(greet(null));

What Node.js prints

TypeError: Cannot read properties of null (reading 'toUpperCase')

Why, and the fix

A default is used only when the argument is missing or undefined. null was passed on purpose, so name is null and has no toUpperCase. If a caller may pass null, call greet(undefined) instead, or check for null in the body before using the value.

A rest parameter that is not last

function order(...items, customer) {
  return customer + ": " + items.length;
}
console.log(order("tea", "cake", "Ada"));

What Node.js prints

SyntaxError: Rest parameter must be last formal parameter

Why, and the fix

A rest parameter takes everything that is left, so nothing can come after it, and the file cannot even be read. Put the single parameters first and the rest parameter last: function order(customer, ...items), and call it as order("Ada", "tea", "cake").

JavaScript in the browser: your browser’s own engine, in a sandboxed worker. Syntax errors are located with acorn 8.18.0, MIT. Licence and source

Exit ticket

5 questions, no hints. Score 80% or more to complete the lesson.

Finish every activity above to unlock the exit ticket.

Report a problem

Spotted something wrong or unclear? Say what, and it will be checked and fixed.

#

At least 20 characters.

Only if you want a reply.

Key ideas

A missing argument is undefined

JavaScript does not check how many arguments a call passes. A parameter with no argument holds undefined, and extra arguments are ignored. So function add(a, b) { return a + b; } called as add(2) gives NaN, because 2 + undefined is not a number. A string method on a missing argument stops the program: text.toUpperCase() with text undefined gives TypeError: Cannot read properties of undefined (reading 'toUpperCase'). When undefined or NaN comes out of a function, first check whether every argument was passed.

Default values

Write = and a value after a parameter to give it a default: function greet(name = "guest"). The default is used when the argument is missing or is undefined, and only then. null, 0, "" and false are real values, so greet(null) gives Hello, null. A default can use the parameters before it: function box(width, height = width). Put parameters with defaults after those without, so that callers can leave them off at the end. To get a default in the middle, pass undefined: orderLine("funghi", undefined, "olives").

Rest parameters collect the rest

Three dots in front of the last parameter, as in function total(...prices), collect all remaining arguments into one real array. With no arguments left it is an empty array, never undefined, so prices.length and for (const p of prices) always work. Only the last parameter can be a rest parameter: function f(...items, last) gives SyntaxError: Rest parameter must be last formal parameter. The same dots in a call do the opposite: total(...basket) spreads an array into separate arguments. That is only a preview here; module B5 teaches spread.

Sources

Last reviewed October 3, 2026