JAVASCRIPT • FUNCTIONS AND PROGRAM STRUCTURE

Default & Rest Parameters — Use default parameters and rest parameters (...args)

Write flexible functions that gracefully handle missing arguments and accept any number of inputs.

Historical Context & Motivation

Before 2015, JavaScript developers faced a persistent annoyance: functions had no built-in way to assign fallback values to parameters. If you called a function without supplying every argument, those missing parameters silently became undefined, which frequently caused bugs. Developers relied on clunky workarounds like x = x || 5 inside the function body, but this pattern had its own problems — it would replace legitimate values like 0 or false with the fallback too.

Similarly, handling a variable number of arguments was awkward. JavaScript provided a hidden arguments object inside every function, but it was not a true array. You couldn't use methods like .map() or .filter() on it directly, which meant extra conversion steps and confusing code.

1995
JavaScript Is Born
Brendan Eich creates JavaScript in 10 days at Netscape. Functions accept any number of arguments, but there is no formal way to set defaults or gather extras.
1999
ES3 Standardizes the arguments Object
ECMAScript 3 formalizes the arguments object — an array-like structure available inside every function. Developers use it to handle variable arguments, but its quirks cause many headaches.
2009
CoffeeScript Inspires Change
CoffeeScript, a language that compiles to JavaScript, introduces default parameters and splats (rest-like syntax). Its popularity pressures the JavaScript standards committee to modernize.
2015
ES6 (ES2015) Arrives
ECMAScript 2015 officially introduces default parameters and rest parameters (...args). These features are now standard in all modern browsers and Node.js.

The central question ES6 answered was straightforward: How can we make functions more flexible and readable when dealing with missing or variable-length arguments? Default and rest parameters were the elegant solution.

Core Principles & Definitions

Default and rest parameters both solve the same broad problem — making functions more adaptable — but they attack it from different angles. Understanding both features together will make your functions shorter, clearer, and less prone to errors.

1

Default Parameters

A default parameter assigns a fallback value to a function parameter. If the caller omits that argument (or passes undefined), the default value is used instead.
2

Rest Parameters

A rest parameter uses the ... syntax to collect all remaining arguments into a real JavaScript array. It must be the last parameter in the function signature.
3

undefined vs. Other Falsy Values

Default parameters trigger only when the argument is undefined. Passing null, 0, or "" will NOT trigger the default — the passed value is used as-is.
4

True Array, Not arguments

Unlike the old arguments object, a rest parameter is a genuine Array. You can immediately use .map(), .reduce(), .filter(), and any other array method.
✦ KEY TAKEAWAY
Think of a function like ordering a sandwich. Default parameters are like the "default toppings" — if you don't specify a bread type, the shop uses wheat. Rest parameters are like saying "…and whatever else you want" — you can toss in as many extra toppings as you like, and they all get collected into one list.

Visual Explanation

This diagram traces a function call through each parameter. The first argument is undefined, so the default value "World" is used. The remaining arguments are gathered by the rest parameter into a real array.

Notice two key details in the diagram above. First, the default parameter only activates when the caller passes undefined (or omits the argument entirely). If we had passed an empty string "", the name would have been the empty string — not "World". Second, the rest parameter ...titles creates a clean array, which means you can chain array methods on it right away.

How It Works — Syntax Deep Dive

Default Parameter Syntax

To set a default parameter, you use the assignment operator = directly in the function signature. This tells JavaScript: "If this argument is not provided or is undefined, use this fallback instead."

DEFAULT PARAMETER PATTERN
function fn(param₁ = defaultValue₁, param₂ = defaultValue₂) { … }
Each parameter can have its own default. Defaults are evaluated left to right, so a later default can reference an earlier parameter: function area(w, h = w) { return w * h; }

Rest Parameter Syntax

The rest parameter uses three dots ... before a parameter name. It gathers all remaining arguments into a real array. There are two hard rules: (1) there can be only one rest parameter per function, and (2) it must be the last parameter in the list.

REST PARAMETER PATTERN
function fn(param₁, param₂, ...restArray) { … }
If the caller passes 5 arguments and there are 2 named parameters, restArray will contain the remaining 3 values as an Array of length 3.

Combining Both Features

You can use default parameters and rest parameters in the same function. The defaults come first, and the rest parameter is always last. For example, function log(level = "INFO", ...messages) gives level a default of "INFO" and collects all remaining arguments into the messages array. This pattern is extremely common in real-world codebases.

⚠️ Common Pitfall
A rest parameter cannot have a default value. Writing ...args = [] is a syntax error. However, if no extra arguments are passed, the rest parameter is simply an empty array [], so you rarely need a default for it anyway.

Old Way vs. New Way — Side-by-Side

The best way to appreciate default and rest parameters is to compare ES5 (the old way) and ES6 (the modern way) side by side. The diagram below shows identical logic written both ways.

Left panels show the pre-ES6 approach with its verbose workarounds. Right panels show the clean ES6 syntax. The old default pattern had a subtle bug with falsy values, while the modern approach handles edge cases correctly.
Key differences between ES5 workarounds and ES6 parameter features
FeatureES5 (Old Way)ES6 (Modern Way)
Setting defaultsx = x || fallbackfunction fn(x = fallback)
Handles 0 / "" correctly?❌ No — treats them as missing✅ Yes — only undefined triggers default
Gathering extra argsArray.from(arguments)function fn(...args)
Result is a real Array?❌ No — must convert✅ Yes — it's already an Array
Works in arrow functions?❌ arguments not available✅ Yes — rest works everywhere

Worked Example — Building a Flexible Logger

Let's build a real-world utility function that uses both default and rest parameters. We'll create a log function that accepts an optional severity level and any number of messages to print.

Building a Flexible Logger Function
1
Step 1 — Define the Function SignatureWe want a severity level that defaults to "INFO" if not provided, followed by any number of message strings. The rest parameter must come last.
function log(level = "INFO", ...messages)
2
Step 2 — Build the Function BodyInside the function, we create a timestamp string, then join all messages with a space. Since messages is a real array, we can call .join(" ") directly on it.
const timestamp = new Date().toISOString(); const output = messages.join(" ");
3
Step 3 — Format and Print the OutputWe use a template literal to combine the timestamp, level, and joined messages into a formatted log string, then print it with console.log().
console.log(`[${timestamp}] [${level}] ${output}`);
4
Step 4 — Test with Various CallsCalling log("ERROR", "File", "not", "found") sets level to "ERROR" and collects the three remaining strings. Calling log(undefined, "Server", "started") triggers the default, so level becomes "INFO".
Output 1: [2025-01-15T...] [ERROR] File not found | Output 2: [2025-01-15T...] [INFO] Server started
5
Step 5 — Complete FunctionHere is the full function combining all the pieces. Notice how clean it is compared to the ES5 approach — no manual argument checking, no array conversion, and the signature itself documents the expected inputs.
function log(level = "INFO", ...messages) { const timestamp = new Date().toISOString(); console.log(`[${timestamp}] [${level}] ${messages.join(" ")}`); }

Strengths, Limitations & Best Practices

Strengths and limitations of default and rest parameters
FeatureStrengthsLimitations / Gotchas
Default ParametersCleaner code; self-documenting signatures; correctly handles 0, "", and falseDefaults are evaluated at call time (not declaration), so using mutable objects like arrays or objects as defaults creates a new one each call — which is usually fine, but be aware of it.
Rest ParametersProduces a real Array; works in arrow functions; clearly communicates intent in the signature.Must be the last parameter. Only one allowed per function. Cannot have a default value assigned to it.
Combined UseExtremely expressive — a single function can handle many calling patterns without conditional logic.If overused, functions can become ambiguous. Keep parameter lists under 4–5 items; use an options object for more.
💡 BEST PRACTICE TIP
Place parameters with defaults at the end of the parameter list (before any rest parameter). This way, callers can simply omit trailing arguments instead of explicitly passing undefined. For example, function createUser(name, role = "viewer") lets you call createUser("Alice") cleanly.

Connection to Advanced Patterns

Default and rest parameters are foundational features that connect to several more advanced JavaScript patterns you'll encounter as you progress. Understanding them now sets you up for destructuring, spread syntax, and functional programming techniques.

How default and rest parameters connect to advanced JavaScript patterns
This Lesson's ConceptAdvanced ConnectionHow They Relate
Default parametersDestructuring with defaultsYou can combine destructuring and defaults: function draw({ color = "red", size = 10 } = {}) {}. This is the standard pattern for options objects.
Rest parametersSpread syntaxThe ... operator does double duty: in a parameter list it gathers (rest), in a function call it spreads. Math.max(...myArray) uses spread to expand an array into arguments.
Rest parametersHigher-order functionsRest parameters are essential for writing wrapper functions, decorators, and middleware — patterns where a function passes all its arguments through to another function.
Both featuresTypeScriptTypeScript adds static types to default and rest parameters. You'll write function sum(...nums: number[]): number for type-safe variadic functions.

As you advance, you'll see these features everywhere — in React component props, Express.js route handlers, and utility libraries. Mastering them now gives you a solid foundation for writing clean, professional JavaScript.

Practice Problems

PROBLEM 1 — CONCEPTUAL
Consider the function function greet(name = "friend") { return "Hi, " + name; }. What does greet(null) return? Explain why.
PROBLEM 2 — BASIC CALCULATION
Write a function multiply(a, b = 1) that returns the product of a and b. What does multiply(7) return? What does multiply(7, 0) return?
PROBLEM 3 — INTERMEDIATE
Write a function average(...numbers) that accepts any number of numeric arguments and returns their arithmetic mean. If no arguments are passed, it should return 0. Test it with average(10, 20, 30) and average().
PROBLEM 4 — APPLIED
You're building a shopping cart. Write a function calculateTotal(taxRate = 0.08, ...prices) that sums all the prices and applies the given tax rate. For example, calculateTotal(0.10, 25, 15, 30) should return 77 (70 + 10% tax). What does calculateTotal(undefined, 50, 50) return?
PROBLEM 5 — CRITICAL THINKING
A teammate writes this function: function createTag(tag = "div", ...classes, id) { /* ... */ }. Before running the code, predict what will happen. Then redesign the function signature so it correctly accepts a tag name (default "div"), any number of CSS class names, and an optional id.

Summary — Default & Rest Parameters

Default parameters let you assign fallback values directly in a function's signature using the = operator. They activate only when the argument is undefined or omitted, which means passing null, 0, or "" will not trigger the default. Later defaults can reference earlier parameters, enabling expressive patterns like function area(w, h = w).

Rest parameters use the ... (three-dot) syntax to collect all remaining arguments into a real JavaScript Array. They must be the last parameter in the function signature, and only one is allowed per function. Together, these two ES6 features replace the old || fallback trick and the clunky arguments object, making your functions shorter, safer, and easier to read.

Varsity Tutors • JavaScript • Default & Rest Parameters