Default Parameters
Clean Defaults Without Falsy Traps
LinkedIn Hook
You ship this helper:
function fee(amount) { amount = amount || 10; return amount * 0.05; }.QA files a bug: "When I pass
0, the fee is0.5, not0."Because
0 || 10is10. And"" || "Guest"is"Guest". Andfalse || trueistrue. The classic falsy-OR trick quietly clobbers every legitimate falsy value your API actually cares about.ES6 default parameters fix this with one rule: they trigger only when the argument is
undefined. Not null. Not 0. Not "". Not false.In this lesson you'll learn the exact trigger rule, how later parameters can reference earlier ones, how defaults compose with destructuring, and the TDZ edge case that trips up senior engineers.
If you still write
x = x || default— this is the lesson that retires that pattern.Read the full lesson -> [link]
#JavaScript #InterviewPrep #ES6 #DefaultParameters #Frontend #CodingInterview #CleanCode
What You'll Learn
- The
undefined-only trigger rule and why it beats the||fallback idiom - Referencing earlier parameters (left-to-right evaluation, TDZ for later names)
- Default parameters combined with destructuring — the canonical
({ ... } = {})pattern
Why Defaults Matter
Before ES6, handling default values meant writing param = param || fallback — which broke on falsy values like 0, "", and false. Default parameters provide a clean, correct solution. Think of them like a restaurant order: "I'll have the special, unless I specify otherwise."
Basic Syntax
// ES5 way — broken for falsy values
function greetOld(name) {
name = name || "Guest"; // "" and 0 would also trigger default
return `Hello, ${name}!`;
}
// ES6 default parameters — only triggers on undefined
function greet(name = "Guest") {
return `Hello, ${name}!`;
}
greet("Rakibul"); // "Hello, Rakibul!"
greet(); // "Hello, Guest!"
greet(undefined); // "Hello, Guest!" — undefined triggers default
greet(null); // "Hello, null!" — null does NOT trigger default
greet(""); // "Hello, !" — empty string does NOT trigger
greet(0); // "Hello, 0!" — 0 does NOT trigger
Expressions as Defaults
Default values can be any expression — including function calls:
function getDefaultAge() {
console.log("Computing default age...");
return 25;
}
function createUser(name = "Guest", age = getDefaultAge()) {
return { name, age };
}
createUser("Rakibul", 30); // getDefaultAge() is NOT called
createUser("Rakibul"); // getDefaultAge() IS called — lazy evaluation
Accessing Earlier Parameters
Later parameters can reference earlier ones:
function createRange(start = 0, end = start + 10, step = 1) {
return { start, end, step };
}
createRange(); // { start: 0, end: 10, step: 1 }
createRange(5); // { start: 5, end: 15, step: 1 }
createRange(5, 20); // { start: 5, end: 20, step: 1 }
// But earlier params CANNOT reference later ones
function broken(a = b, b = 1) {} // ReferenceError — TDZ for 'b'
Default with Destructuring
// Destructured object with defaults
function createUser({ name = "Guest", age = 25, role = "user" } = {}) {
return { name, age, role };
}
createUser({ name: "Rakibul" }); // { name: "Rakibul", age: 25, role: "user" }
createUser(); // { name: "Guest", age: 25, role: "user" }
// Array destructuring with defaults
function first([a = 0, b = 0] = []) {
return a + b;
}
first([5, 3]); // 8
first([5]); // 5
first(); // 0
Default Parameter Scope (TDZ)
Default parameters have their own scope — they exist in a middle ground between the outer scope and the function body:
let x = 1;
function foo(x = 2, y = () => x) {
// The 'x' in y's closure is the parameter x, not the body x
let x = 3; // This is a different x (function body scope)
console.log(y()); // 2, not 3
}
foo(undefined); // Logs: 2 — y() captures parameter x, not body x
Common Mistakes
- Relying on
x = x || defaultfrom ES5 muscle memory — that swaps in the default for every falsy value, silently corrupting0,"", andfalseinputs. Default parameters fire only onundefined. - Referencing a parameter that hasn't been evaluated yet, like
function f(a = b, b = 1) { ... }— parameters evaluate left-to-right, andbis in its TDZ whena's default runs. Always put the referenced parameter first. - Forgetting the
= {}safety net on destructured parameters —function f({ a = 1 })throws when called with no argument, because you can't destructureundefined. Writefunction f({ a = 1 } = {}).
Interview Questions
Q: When does a default parameter get used?
A default parameter is only used when the argument is
undefined— either not passed or explicitly passed asundefined. Other falsy values (null,0,"",false) do NOT trigger the default.
Q: Can a default parameter reference another parameter?
Yes, a later parameter can reference an earlier one (
function f(a = 1, b = a + 1)), but NOT the reverse. Parameters are evaluated left to right and the temporal dead zone (TDZ) applies, so referencing a later parameter throws a ReferenceError.
Q: What is the TDZ edge case with default parameters?
Default parameters have their own scope. A function like
function f(x = 2, y = () => x) { let x = 3; return y(); }returns 2, not 3 — becauseycloses over the parameterx, not the body-scopedx. This is because default params create an intermediate scope.
Q: How do you safely destructure an options argument with defaults?
Combine destructuring defaults with a parameter default of
{}:function f({ name = "Guest", age = 25 } = {}) { ... }. The outer= {}ensures the function works when called with no argument at all; the inner defaults handle missing properties.
Quick Reference — Cheat Sheet
DEFAULT PARAMETERS — QUICK MAP
Trigger rule:
argument === undefined -> default fires
null, 0, "", false, NaN -> default does NOT fire
Syntax:
function f(x = 10) -> primitive default
function f(x = getDefault()) -> lazy expression default
function f(a = 1, b = a + 1) -> later references earlier
function f({ x = 1 } = {}) -> destructuring + outer guard
function f([a = 0, b = 0] = []) -> array destructuring
Do not:
function f(a = b, b = 1) -> ReferenceError (b in TDZ)
x = x || default -> breaks on 0, "", false
Previous: Arrow Functions -> Lexical this and Shorter Syntax Next: let, const, Block Scoping -> Patterns and Edge Cases
This is Lesson 9.3 of the JavaScript Interview Prep Course — 14 chapters, 87 lessons.