completefrontend
Open lab My progress
THE JAVASCRIPT FIELD GUIDE

Default & rest parameters

Handle missing JavaScript arguments, collect any number of inputs, understand the old arguments object, spread arrays into calls, and design flexible functions.

By the end, you can
  • 01
    Use defaultsSay exactly when a default parameter is used: for a missing argument or undefined, but not for null or 0.
  • 02
    Collect many argumentsUse a rest parameter to collect any number of arguments into an array, instead of the old arguments object.
  • 03
    Pass an array's valuesUse spread to pass an array's values as separate arguments, like Math.max(...scores).

Five tools for function inputs

A parameter is a name in the brackets of a function, like customer in function showOrder(customer). An argument is the value you pass in when you call the function, like "Asha". You met both in Declaring & calling functions. This lesson shows five tools that make function inputs easier to work with.

JavaScript doesn't check how many arguments you pass. A missing argument becomes undefined. An extra argument is ignored, unless the function asks for it. The five tools let a function say clearly what it wants:

  • Default parameters give a parameter a value to use when its argument is missing.
  • Rest parameters collect any number of arguments into one array. An array is a list of values in square brackets, like [1, 2, 3].
  • Spread in a call does the opposite. It takes the values out of an array and passes them as separate arguments.
  • The arguments object is an older way to see every argument that was passed.
  • An options object passes many settings as one object, each with a name. It lets one function be called in several ways.
Arguments fill parameters from left to rightPop out in the code editor (opens in a new tab)JavaScript
function showOrder(customer, drink) {
  console.log(customer, drink);
}
showOrder("Asha", "tea");
showOrder("Asha");
showOrder("Asha", "tea", "cake");

Line 1 makes a function with two parameters, customer and drink. Line 2 prints both. Line 4 passes two arguments, so customer is "Asha" and drink is "tea". It prints Asha tea.

Line 5 passes only one argument, so drink is undefined. It prints Asha undefined. Line 6 passes three arguments. The function has no third parameter, so "cake" is ignored. It prints Asha tea.

The call showOrder with Asha, tea, and cake. Asha goes into the box customer. tea goes into the box drink. cake has no box, so it is ignored.showOrder("Asha", "tea", "cake")"Asha"customer1st argument"tea"drink2nd argument"cake"ignored
Arguments fill the parameters from left to right. "Asha" goes into customer and "tea" goes into drink. There is no third parameter, so "cake" is ignored.
Real-life analogyA form with a field already filled in

Think of an address form on a shop website. The Country field already says United States. If you leave it, the form uses United States. If you type something else, the form uses what you typed, even if it is odd. A default parameter works the same way.

In real life: The Country field already says United States
In JavaScript: function ship(country = "United States")
In real life: You leave the field as it is, so the form uses United States
In JavaScript: Call ship() with no argument, or pass undefined
In real life: You type Canada, so the form uses Canada
In JavaScript: Pass "Canada"; the default is not used
In real life: You type 0 by mistake, and the form still saves 0
In JavaScript: Pass 0; a default doesn't check whether a value makes sense

Keep one rule in mind for this lesson: a default is used only when an argument is missing. It is not used for every value that looks empty, like 0 or "". This is different from ||, which you may have seen used for fallback values. || replaces any falsy value: a value that counts as false in an if.

Default parameters

STEP THROUGH

To give a parameter a default, write = value after its name, inside the function's brackets. It means: "If the caller doesn't give me this value, use this one."

A parameter with a defaultPop out in the code editor (opens in a new tab)JavaScript
function greet(name = "friend") {
  return "Hello, " + name;
}

greet();        // "Hello, friend"
greet("Ada");  // "Hello, Ada"

Line 1 gives name the default "friend". Line 5 calls greet() with no argument, so name is "friend". Line 6 passes "Ada", so the default is not used.

Which values use the default, exactly? Step through this run. You can change the call on line 5. Watch null and 0 closely: they do not use the default.

When is the default used?
Step 0 of 4Ready
Your turn: follow the blue line

Change the call on line 5. Guess whether the default is used, then step through.

Running in
  1. script
Next: line 5
function greet(name = "friend") {  const message = "Hello, " + name;  console.log(message);}
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
Change the call on line 5

Changing the call starts the replay again. Guess the printed line first.

A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.
Left: the call greet() passes nothing, so the box name gets the default, friend. Right: the call greet(null) passes null, so the box name keeps null and the default is not used.greet()"friend"namedefault usedgreet(null)nullnamedefault not used
The default "friend" is used only when the argument is missing or undefined. null is a real value, so name keeps null.
Defaults and ?? check different things

A default parameter is used when the argument is missing or exactly undefined. The ?? operator gives a fallback when a value is null or undefined. So they are close, but they treat null differently.

A default can use a parameter that comes before it. JavaScript fills parameters from left to right, so the earlier one already has its value. This helps when two values are often the same:

A default that uses an earlier parameterPop out in the code editor (opens in a new tab)JavaScript
function box(width, height = width) {
  return width + " × " + height;
}

box(5);     // "5 × 5"
box(5, 2);  // "5 × 2"

Line 1 says: if height is missing, use width. Line 5 passes only 5, so it returns "5 × 5". Line 6 passes both values, so it returns "5 × 2".

Be careful with order. Look at function label(prefix = "Item", text). The call label("Save") puts "Save" into prefix, the first parameter, not into text. So text is undefined. Put the parameters the caller must give first, and the ones with defaults after them. If there are many optional values, use an options object. You'll see one later in this lesson.

A default is made fresh for each call

STEP THROUGH

JavaScript works out a default's value each time a call needs it. It does not work it out once, when the function is made. So Date.now() as a default would give the current time for each call. And [] as a default makes a new, empty array for each call.

Each call gets a new default array
Step 0 of 8Ready
Your turn: follow the blue line

Step through both calls. Watch each call get its own new array.

Running in
  1. script
Next: line 5
function remember(item, list = []) {  list.push(item);  console.log(list.join(","));}remember("cake");
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Lines 5 and 6 each call remember with no list. Each call gets its own new array. So the second call prints cake, not tea,cake. Some other languages make a default array only once and share it between calls. JavaScript doesn't.

A passed-in array is not a copy

The new array is made only when the caller leaves the argument out. If the caller passes an array, the function gets that same array, not a copy. Changes made inside the function show up outside it too.

A string is copied; an object is sharedPop out in the code editor (opens in a new tab)JavaScript
function update(name, user) {
  name = "Mina";
  user.name = "Mina";
}
const name = "Asha";
const user = { name: "Asha" };
update(name, user);
console.log(name);
console.log(user.name);

Line 7 calls update with a string and an object. The parameter name gets its own copy of the string "Asha". Line 2 changes only that copy, so line 8 still prints Asha.

The parameter user points to the same object as the outer user. Line 3 changes that object's name property, so line 9 prints Mina.

Rest parameters

INTERACTIVE

Sometimes a function should take any number of values: no scores, three tags, or five names. A rest parameter does this. Write three dots before the last parameter's name, like ...numbers. Every argument that is left over goes into an array with that name.

Choose how many numbers to pass
A rest parameter that adds numbersPop out in the code editor (opens in a new tab)JavaScript
function sum(...numbers) {  let total = 0;  for (const number of numbers) {    total = total + number;  }  return total;}
What the call gives2 arguments

Call: sum(4, 8)

numbers array: [4, 8]

Array.isArray(numbers): true

Returned total: 12

Try it yourself

The rest parameter makes numbers = [4, 8]. It is a real array with 2 items. The function adds them up and returns 12.

A rest parameter collects every argument that is left after the normal parameters. This function has no normal parameters, so it collects all of them.

Pick a few calls above. Each time, numbers is a real array, even when it is empty.

The call sum with 1, 2, and 3. Three separate value cards, 1, 2, and 3, go along an arrow into one box called numbers, which holds the array 1, 2, 3.sum(1, 2, 3)123three values[1, 2, 3]numbersone array
sum(1, 2, 3) passes three separate values. The rest parameter ...numbers collects them into one array, [1, 2, 3].

A rest parameter must be the last parameter. It takes every argument that is left. If another parameter came after it, no argument would be left for that one.

A rest parameter must come lastPop out in the code editor (opens in a new tab)JavaScript
function log(level, ...messages) { // OK: rest is last
  return messages.length;
}

function bad(...items, last) { // SyntaxError: rest is not last
  return last;
}

Line 1 is fine: level takes the first argument, and messages takes the rest. Line 5 puts last after the rest parameter. JavaScript refuses to run this code and throws a SyntaxError. A syntax error means the code is not written in a form JavaScript accepts.

Real-life analogyA bag for everything else

You pack for a picnic. The sandwich goes in your hand, because it has its own job. Every other snack goes into one bag. A rest parameter is that bag, for arguments.

In real life: You hold the sandwich in your hand
In JavaScript: A normal parameter like level takes one argument
In real life: Every other snack goes into one bag
In JavaScript: ...messages collects the rest
In real life: You look in the bag and count the snacks
In JavaScript: Use array tools like .length or for...of

A rest parameter is a real array, so you can loop over it with the for...of loop from earlier. Arrays get their own lessons in Stage 3. For now, you only need to know that a rest array has:

  • a length, which says how many values it holds,
  • numbered positions starting at 0, like numbers[0],
  • array methods, like .join and .map.

The old arguments object

STEP THROUGH

Before rest parameters existed, functions used the arguments object. JavaScript makes it for you inside every function written with the function keyword. It holds every argument that was passed. You'll see it in older code. In new code, use a rest parameter instead.

Look inside the old arguments object
Step 0 of 6Ready
Your turn: follow the blue line

Step through the old arguments object. Then compare it with a rest parameter.

Running in
  1. script
Next: line 6
function inspect() {  console.log(arguments.length);  console.log(arguments[0]);  console.log(Array.from(arguments).join(" | "));}
CallStoreChangeResultBlue line: runs next. Ran: already executed.
Recent returnsNothing yet. Start with the blue line.
A guided replay recorded from real JavaScript calls, not an engine debugger. Step follows executed statements; Back reviews a snapshot. Reset starts a fresh run.

Line 2 prints how many arguments there are: 3. Line 3 reads the first one, "Ada", at position 0. Line 4 turns arguments into a real array with Array.from, then joins the names into one string.

Why arguments.map failsPop out in the code editor (opens in a new tab)JavaScript
function broken() {
  return arguments.map((value) => value);
}
broken(1, 2, 3);

Line 2 throws a TypeError. The arguments object is array-like: it has numbered positions and a length, like an array. But it doesn't have array methods such as .map.

To fix it, turn it into an array first with Array.from(arguments). Or better, write function broken(...values) and use values.map.

Arrow functions have no arguments object

Arrow functions, like (x) => x * 2, don't get their own arguments object. The Arrow functions lesson explains this. It is one more reason to use rest parameters in new code.

Spread in a function call

SORT

The same three dots do the opposite job inside a function call. Rest collects many arguments into one array. Spread takes one array and passes each of its values as a separate argument. Spread works on arrays, and on other values you can loop over with for...of, like strings.

Real-life analogyUnpacking a grocery bag

The cashier can't scan a closed bag. You take each item out and put it on the counter. Spread does that for a function call.

In real life: A bag with apples, bread, and milk
In JavaScript: An array like scores
In real life: Put each item on the counter, one by one
In JavaScript: Write ...scores in a call
In real life: The cashier scans each item
In JavaScript: The function gets each value as its own argument
Pass an array's values as separate argumentsPop out in the code editor (opens in a new tab)JavaScript
const scores = [18, 7, 21];
console.log(Math.max(...scores));
console.log(Math.max(10, ...scores, 30));

Line 1 makes an array of three scores. Math.max is a built-in function that returns the biggest of its arguments. It wants separate numbers, not one array.

Line 2 spreads the array, so it works like Math.max(18, 7, 21) and prints 21. Line 3 mixes normal arguments with spread. It works like Math.max(10, 18, 7, 21, 30) and prints 30.

Math.max(...scores). The box scores holds the array 18, 7, 21. An arrow takes the values out as three separate cards: 18, 7, and 21.Math.max(...scores)[18, 7, 21]scoresone array18721three values
The opposite of rest. ...scores takes the values out of the array, so Math.max gets three separate arguments: 18, 7, and 21.

Rest and spread both use three dots, so they are easy to mix up. Each row of the table below asks one question and answers it for rest and for spread.

How rest and spread differ
QuestionRestSpread
Where do the dots go?In a function's parameter list.In a function call. You can also use them inside a new array or object you are writing.
Which way do values move?Many arguments go in, and one array comes out.One array goes in, and many separate arguments come out.
What does it look like?function sum(...numbers) {}sum(...numbers)
What is a common mistake?Putting another parameter after it.Spreading a value that isn't a list, like a number. That throws a TypeError.
Rest or spread?
  • function sum(...numbers) { }
  • Math.max(...scores)
  • function log(level, ...messages) { }
  • send('info', ...messages)
  • greet(...names)
  • function tag(first, ...rest) { }
Try it yourself
0 of 6 correct

Sort each line by what its three dots do. Ask: are the dots in a function's parameter list, or in a call?

Choose a category for every card. You can change an answer at any time; Reset clears them all.

One function, many ways to call it

In some languages, you can write several functions with the same name but different parameters. The language picks one, based on what you pass. This is called overloading. JavaScript doesn't have it. If you write two functions with the same name, the second one replaces the first.

Instead, write one function that checks what it was given. For small cases, it can check:

  • arguments.length: how many arguments came in,
  • typeof: what type a value is, like "string",
  • Array.isArray: whether a value is an array.

For real code, the most common way is an options object: one object argument with named settings, each with a default.

An options object with defaultsPop out in the code editor (opens in a new tab)JavaScript
function createUser({ name = "Anonymous", role = "viewer" } = {}) {
  return name + " (" + role + ")";
}
console.log(createUser({ name: "Ada" }));
console.log(createUser({ name: "Grace", role: "admin" }));
console.log(createUser());

Line 1 has one parameter: an object in curly braces. The braces take the name and role properties out of that object and make them into variables. This is called destructuring. A later lesson covers it fully.

  • name and role each have their own default.
  • The = {} at the end gives the whole object a default. So createUser() with nothing passed doesn't throw.

Line 4 gives only a name, so role is "viewer". Line 5 gives both. Line 6 gives nothing, so both defaults are used, and it prints Anonymous (viewer).

Where you’ll use this

Many real functions grow optional settings: a logger, a date formatter, or a helper that talks to a server. An options object keeps each call easy to read. Compare createUser({ name: "Ada", role: "admin" }) with createUser("Ada", true, false, "admin"). In the second call, you can't tell what true and false mean.

Property defaults are used only for undefinedPop out in the code editor (opens in a new tab)JavaScript
function badge({ label = "New", count = 0 } = {}) {
  return label + ":" + count;
}
console.log(badge({ label: "Cart" }));
console.log(badge({ label: undefined, count: null }));

Line 4 leaves out count, so count uses its default, 0. It prints Cart:0.

Line 5 passes undefined for label, so label uses its default, "New". It passes null for count, and null is kept. It prints New:null.

Common mix-ups

"Defaults are used for every falsy value."

No. A default is used only when the argument is missing or undefined. Falsy values count as false in an if, but null, 0, false, and "" are still values the caller chose. They are kept.

"Rest and spread are the same, because both use three dots."

No. They do opposite jobs. Rest is in a function's parameter list and collects arguments into an array. Spread is in a call and takes values out of an array.

"The arguments object is an array."

No. It has numbered positions and a length, but no array methods like .map. Turn it into an array with Array.from, or use a rest parameter.

"A rest parameter can go anywhere in the list."

No. It must be last. It takes every argument that is left, so no argument could reach a parameter after it.

"JavaScript picks the right version of a function for me."

No. JavaScript calls whatever function is saved under that name. It doesn't look at the types or the number of arguments. Put the checks inside one function.

Practice: flexible function inputs

5 EXERCISES

Start by guessing what a short program prints. Then write small functions that use rest, spread, and an options object. Try each one first, then use the hints if you get stuck.

Exercise 1 · Warm-upPredict when the default is used

Guess the three printed lines. Type them in order, separated by commas.

Starter codePop out in the code editor (opens in a new tab)JavaScript
function label(value = "empty") {
  console.log(value);
}
label(undefined);
label(null);
label(0);

Answer, then press Check. Spacing and letter case don’t matter.

    Exercise 2 · PracticeWrite average(...nums)

    Write a function that returns the average of any number of arguments. With no arguments, it should return 0.

    Starter codePop out in the code editor (opens in a new tab)JavaScript
    function average(...nums) {
      // return 0 when there are no numbers
    }

    Answer, then press Check. Spacing and letter case don’t matter.

      Exercise 3 · PracticeReplace arguments with a rest parameter

      Rewrite the function with a rest parameter. Then check what listNames("Ada", "Grace") prints.

      Starter codePop out in the code editor (opens in a new tab)JavaScript
      function listNames() {
        return Array.from(arguments).join(", ");
      }

      Answer, then press Check. Spacing and letter case don’t matter.

        Exercise 4 · PracticeSpread an array into Math.min

        Use spread to print the smallest number in the array.

        Starter codePop out in the code editor (opens in a new tab)JavaScript
        const scores = [9, 4, 12];
        // print the smallest score

        Answer, then press Check. Spacing and letter case don’t matter.

          Exercise 5 · ChallengeWrite a function that takes an options object

          Write a function that takes { name, role } and gives both properties a default.

          Starter codePop out in the code editor (opens in a new tab)JavaScript
          function createUser(/* options */) {
            // name defaults to "Anonymous"
            // role defaults to "viewer"
          }

          Answer, then press Check. Spacing and letter case don’t matter.

            Quiz: check your understanding

            7 QUESTIONS

            Work out each answer from the code, not from memory. Every answer explains why it is right or wrong.

            Lesson quiz · 7 questionsScore: first tries count
            1. Question 1 of 7When is a default parameter value used?

              Choose an answer to see the explanation.

            2. Question 2 of 7What does greet(null) print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function greet(name = "friend") {
                console.log("Hi " + name);
              }
              greet(null);

              Choose an answer to see the explanation.

            3. Question 3 of 7Which of these functions is valid JavaScript?

              Choose an answer to see the explanation.

            4. Question 4 of 7What does this rest parameter code print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              function count(...items) {
                console.log(Array.isArray(items));
                console.log(items.length);
              }
              count("a", "b");

              Choose an answer to see the explanation.

            5. Question 5 of 7Which statement about arguments is true?

              Choose an answer to see the explanation.

            6. Question 6 of 7What does Math.max(...scores) print?

              Read the code, then predictPop out in the code editor (opens in a new tab)JavaScript
              const scores = [3, 8, 5];
              console.log(Math.max(...scores));

              Choose an answer to see the explanation.

            7. Question 7 of 7JavaScript can't pick between two functions with the same name. How do you let one function be called in several ways?

              Choose an answer to see the explanation.

            Key takeaways

            • A default parameter is used only when its argument is missing or undefined.
            • JavaScript works out a default during each call, so [] makes a new array for every call that needs it.
            • A rest parameter collects the leftover arguments into a real array. It must be the last parameter.
            • arguments is older and array-like, and arrow functions don't have their own. Use a rest parameter instead.
            • Spread in a call takes the values out of an array and passes them as separate arguments.
            • JavaScript has no overloading. Write one function that checks its inputs, or have it take an options object.

            Remember the one-liner.
            Defaults fill in missing arguments, rest collects extra arguments, and spread takes values out of an array for a call.

            Up next: Function expressions & callbacks.

            CompleteFrontend Clear concepts. Working examples.