How to Use Default Parameters in JS Functions
Learn how to use default parameters in JavaScript functions. Covers ES6 default syntax, expressions as defaults, pre-ES6 patterns, how undefined triggers defaults but null does not, and practical patterns for config objects and optional settings.
Default parameters let you assign fallback values to function parameters when no argument is passed. Before ES6, developers used || or manual undefined checks to achieve this. ES6 default parameters provide a cleaner, built-in syntax that evaluates the default only when the argument is undefined.
This tutorial covers the full range of default parameter behavior, from basic syntax to advanced patterns like expressions as defaults and referencing other parameters.
The Pre-ES6 Approach
Before default parameters existed, developers used the || operator or explicit checks:
// Pattern 1: OR operator (has a bug)
function greet(name) {
name = name || "Guest";
return `Hello, ${name}!`;
}
console.log(greet("Alice")); // "Hello, Alice!"
console.log(greet()); // "Hello, Guest!"
console.log(greet("")); // "Hello, Guest!" (BUG: empty string is falsy)The || pattern fails with falsy values like "", 0, false, and null. It treats all of them as missing:
// Pattern 2: explicit undefined check (safer but verbose)
function greet(name) {
if (name === undefined) {
name = "Guest";
}
return `Hello, ${name}!`;
}
console.log(greet("")); // "Hello, !" (empty string preserved)
console.log(greet(0)); // "Hello, 0!" (zero preserved)
console.log(greet()); // "Hello, Guest!"| Pattern | Handles undefined | Handles "" | Handles 0 | Clean? |
|---|---|---|---|---|
name || "default" | Yes | Treats as missing | Treats as missing | Short |
name === undefined | Yes | Preserves | Preserves | Verbose |
name ?? "default" | Yes | Preserves | Preserves | Short |
| ES6 default parameter | Yes | Preserves | Preserves | Best |
ES6 Default Parameter Syntax
The = sign after a parameter name assigns a default value:
function greet(name = "Guest") {
return `Hello, ${name}!`;
}
console.log(greet("Alice")); // "Hello, Alice!"
console.log(greet()); // "Hello, Guest!"
console.log(greet(undefined)); // "Hello, Guest!" (explicit undefined triggers default)Multiple Default Parameters
function createUser(name = "Anonymous", role = "viewer", active = true) {
return { name, role, active };
}
console.log(createUser());
// { name: "Anonymous", role: "viewer", active: true }
console.log(createUser("Alice"));
// { name: "Alice", role: "viewer", active: true }
console.log(createUser("Bob", "admin"));
// { name: "Bob", role: "admin", active: true }
console.log(createUser("Charlie", "editor", false));
// { name: "Charlie", role: "editor", active: false }Put Defaults Last
Parameters with defaults should come after required parameters. If a default parameter comes first, you must pass undefined to skip it: createUser(undefined, "admin"). This is confusing. Put required parameters first.
What Triggers the Default Value
Only undefined triggers the default. Any other value, including null, 0, "", and false, is used as-is:
function demo(value = "default") {
return value;
}
console.log(demo()); // "default" (no argument = undefined)
console.log(demo(undefined)); // "default" (explicit undefined)
console.log(demo(null)); // null (NOT replaced)
console.log(demo(0)); // 0 (NOT replaced)
console.log(demo("")); // "" (NOT replaced)
console.log(demo(false)); // false (NOT replaced)| Argument | Triggers default? | Result |
|---|---|---|
| (nothing) | Yes | "default" |
undefined | Yes | "default" |
null | No | null |
0 | No | 0 |
"" | No | "" |
false | No | false |
This is a critical difference from the || pattern, which replaces all falsy values.
Expressions as Default Values
Defaults are not limited to simple values. Any expression works, and it is evaluated at call time, not at definition time:
function createId(prefix = "id", timestamp = Date.now()) {
return `${prefix}_${timestamp}`;
}
console.log(createId()); // "id_1738746000000" (different each call)
console.log(createId("user")); // "user_1738746000000"Function Calls as Defaults
function getDefaultName() {
console.log("Computing default...");
return "Guest";
}
function greet(name = getDefaultName()) {
return `Hello, ${name}!`;
}
greet("Alice"); // "Hello, Alice!" (getDefaultName NOT called)
greet(); // "Computing default..." then "Hello, Guest!"The default expression runs only when the default is actually needed. This is called lazy evaluation.
Referencing Previous Parameters
A default expression can reference parameters declared before it in the parameter list:
function createElement(tag = "div", className = `${tag}-default`) {
return `<${tag} class="${className}">`;
}
console.log(createElement());
// <div class="div-default">
console.log(createElement("section"));
// <section class="section-default">
console.log(createElement("nav", "main-nav"));
// <nav class="main-nav">function createRange(start = 0, end = start + 10) {
const range = [];
for (let i = start; i <= end; i++) {
range.push(i);
}
return range;
}
console.log(createRange()); // [0, 1, 2, ..., 10]
console.log(createRange(5)); // [5, 6, 7, ..., 15]
console.log(createRange(5, 7)); // [5, 6, 7]Forward References Do Not Work
A default cannot reference a parameter that comes after it. function f(a = b, b = 1) throws a [ReferenceError](/tutorials/programming-languages/javascript/basic-javascript-debugging-tips-for-beginners) when called as f() because b is not yet initialized when a tries to use it.
Destructured Parameters with Defaults
Default parameters combine naturally with destructuring:
Object Destructuring
function createButton({ text = "Click", color = "blue", size = "medium" } = {}) {
return `<button class="${color} ${size}">${text}</button>`;
}
console.log(createButton());
// <button class="blue medium">Click</button>
console.log(createButton({ text: "Submit", color: "green" }));
// <button class="green medium">Submit</button>Notice the = {} after the destructuring pattern. This provides a default for the entire object, so calling createButton() with no arguments does not throw an error.
Array Destructuring
function getCoordinates([x = 0, y = 0] = []) {
return `(${x}, ${y})`;
}
console.log(getCoordinates()); // "(0, 0)"
console.log(getCoordinates([5])); // "(5, 0)"
console.log(getCoordinates([3, 7])); // "(3, 7)"Practical Patterns
Configuration Objects
Functions that accept many options benefit from a destructured default object:
function fetchData(url, options = {}) {
const config = {
method: "GET",
timeout: 5000,
retries: 3,
cache: true,
...options,
};
console.log(`Fetching ${url} with:`, config);
return config;
}
fetchData("/api/users");
// method: "GET", timeout: 5000, retries: 3, cache: true
fetchData("/api/users", { method: "POST", timeout: 10000 });
// method: "POST", timeout: 10000, retries: 3, cache: trueRequired Parameter With a Helpful Error
function required(paramName) {
throw new Error(`Missing required parameter: ${paramName}`);
}
function createUser(name = required("name"), email = required("email")) {
return { name, email, createdAt: new Date().toISOString() };
}
createUser("Alice", "alice@test.com"); // works
createUser("Alice"); // Error: Missing required parameter: email
createUser(); // Error: Missing required parameter: nameFeature Toggle with Defaults
function initApp({
darkMode = false,
analytics = true,
debugMode = false,
language = "en",
maxRetries = 3,
} = {}) {
console.log("App initialized with:");
console.log(` Dark mode: ${darkMode}`);
console.log(` Analytics: ${analytics}`);
console.log(` Debug mode: ${debugMode}`);
console.log(` Language: ${language}`);
console.log(` Max retries: ${maxRetries}`);
}
initApp(); // all defaults
initApp({ darkMode: true, language: "es" }); // override two settingsChained Defaults for Validation
function clamp(value, min = 0, max = 100) {
if (value < min) return min;
if (value > max) return max;
return value;
}
console.log(clamp(50)); // 50
console.log(clamp(150)); // 100
console.log(clamp(-10)); // 0
console.log(clamp(50, 10, 60)); // 50
console.log(clamp(5, 10, 60)); // 10Common Mistakes
Mistake 1: Using null Instead of undefined
function greet(name = "Guest") {
return `Hello, ${name}!`;
}
// Passing null does NOT trigger the default
console.log(greet(null)); // "Hello, null!" (not "Hello, Guest!")Mistake 2: Mutable Default Objects
// WRONG: shared reference
function addItem(item, list = []) {
list.push(item);
return list;
}
// This is actually SAFE in JavaScript!
// Unlike Python, the default is evaluated fresh each call
console.log(addItem("a")); // ["a"]
console.log(addItem("b")); // ["b"] (new array each time)Unlike Python, JavaScript evaluates default parameter expressions on each call. So = [] creates a new empty array every time the default is used.
Mistake 3: Skipping Middle Parameters
function create(name = "Item", quantity = 1, price = 9.99) {
return { name, quantity, price };
}
// WRONG: can't skip 'quantity' to set 'price'
// create("Widget", , 19.99); // SyntaxError
// Pass undefined to use the default
create("Widget", undefined, 19.99);
// { name: "Widget", quantity: 1, price: 19.99 }If you frequently skip parameters, switch to an object parameter instead.
Rune AI
Key Insights
- Only
undefinedtriggers defaults:null,0,"", andfalseare used as-is - Defaults are evaluated per call: unlike Python,
= []creates a fresh array each time - Put default parameters last: required parameters first avoids awkward
undefinedplaceholders - Use object destructuring for many options:
function f({ a = 1, b = 2 } = {})scales well - Expressions and function calls work as defaults: they run only when the default is needed
Frequently Asked Questions
What is the difference between default parameters and the OR operator for defaults?
Can I use async functions or await in default parameter expressions?
Do default parameters work with arrow functions?
Is there a performance cost to using default parameters?
Conclusion
Default parameters provide a clean, built-in way to handle missing function arguments in JavaScript. They trigger only when the argument is undefined, preserving intentional falsy values like 0, "", and false. Default expressions are evaluated lazily at call time, can reference earlier parameters, and combine naturally with destructuring for configuration objects.
More in this topic
OffscreenCanvas API in JS for UI Performance
Master the OffscreenCanvas API to offload rendering from the main thread. Covers worker-based 2D and WebGL rendering, animation loops inside workers, bitmap transfer, double buffering, chart rendering pipelines, image processing, and performance measurement strategies.
Advanced Web Workers for High Performance JS
Master Web Workers for truly parallel JavaScript execution. Covers dedicated and shared workers, structured cloning, transferable objects, SharedArrayBuffer with Atomics, worker pools, task scheduling, Comlink RPC patterns, module workers, and performance profiling strategies.
JavaScript Macros and Abstract Code Generation
Master JavaScript code generation techniques for compile-time and runtime metaprogramming. Covers AST manipulation, Babel plugin authorship, tagged template literals as macros, code generation pipelines, source-to-source transformation, compile-time evaluation, and safe eval alternatives.