Default Parameters
ES6 default parameter values — evaluated at call time, temporal dead zone with lets, and why undefined triggers defaults but null does not.
- javascript
- default-parameters
- functions
Default parameters replace the old arg = arg || 'fallback' pattern with something that only kicks in for undefined — not for every falsy value. That single detail fixes bugs with 0 and '' and creates new ones if you pass null expecting a default.
Basics
function greet(name = 'world', punctuation = '!') {
return `Hello, ${name}${punctuation}`;
}
greet(); // "Hello, world!"
greet('Ada'); // "Hello, Ada!"
greet('Ada', '?'); // "Hello, Ada?"
greet(undefined, '?'); // "Hello, world?"
greet(null); // "Hello, null!" — null does NOT trigger default
Only missing arguments and explicit undefined use the default.
Evaluated at call time
function append(x, list = []) {
list.push(x);
return list;
}
append(1); // [1]
append(2); // [2] — fresh array each call
Defaults are re-evaluated per call. You do not share one array across calls (unlike a mutable default in some other languages’ pitfalls — JS got this right).
let id = 0;
function next(n = ++id) {
return n;
}
next(); // 1
next(); // 2
next(99); // 99 — default expression not run
Defaults can use earlier params
function box(width, height = width) {
return { width, height };
}
box(10); // { width: 10, height: 10 }
Later params cannot be referenced from earlier defaults (TDZ):
function broken(a = b, b = 1) {
return [a, b];
}
// broken() → ReferenceError when evaluating a = b
Destructured defaults
function createUser({
name = 'Anonymous',
roles = ['user'],
settings: { theme = 'light' } = {},
} = {}) {
return { name, roles, theme };
}
createUser();
createUser({ name: 'Ada' });
createUser({ settings: { theme: 'dark' } });
The = {} on the whole parameter lets you call createUser() with no args. Nested = {} protects when settings is missing.
vs || and ??
function f(x) {
x = x || 10; // 0 becomes 10 — often wrong
}
function g(x) {
x = x ?? 10; // only null/undefined
}
function h(x = 10) {
// only undefined (and missing)
}
| Input | || |
?? |
default param |
|---|---|---|---|
missing / undefined |
default | default | default |
null |
default | default | keeps null |
0 / '' |
default | keeps | keeps |
arguments and length
function f(a = 1, b = 2) {}
f.length; // 0 — params with defaults don't count toward length from the first default onward
function g(a, b = 2) {}
g.length; // 1
Defaulted parameters also change arguments object mapping in non-simple parameter lists — prefer rest/explicit params in modern code.
Interview answer
“Default parameters apply when the argument is missing or undefined, not null or other falsy values. Default expressions run at call time, so [] as a default is safe. I use them with destructuring for option objects, and I pick ?? when I need null to fall back outside parameter lists.”
Related
Temporal dead zone with defaults
function order(a = b, b = 2) {
return [a, b];
}
// order() → ReferenceError: Cannot access 'b' before initialization
function ok(a, b = a) {
return [a, b];
}
ok(1); // [1, 1]
Default expressions see earlier parameters, outer scope, and the function’s own bindings carefully — but not later parameters. Also: reassigning a defaulted parameter does not update arguments[i] in modern non-mapped parameter lists; don’t mix arguments with defaults.
Further reading
Related guides
- Arrow Functions Deep DiveLexical this, no arguments object, no construct, concise bodies — when arrows help and when methods and generators need classic functions.
- Currying and Partial ApplicationCurry vs partial application — unary chains, bind, practical helpers, and when extra abstraction hurts readability.
- AbortControllerCancel fetch and other async work with AbortController and AbortSignal — timeouts, race conditions, and cleanup when components unmount.
- Array find, some, every, includesShort-circuiting array predicates: find, findIndex, some, every, and includes — when to use each and common interview traps.
- Array map, filter, reducemap, filter, and reduce as the core transform toolkit — immutability, chaining costs, reduce patterns, and when a plain loop is clearer.