Default Parameters
Before ES2015, the way to give a parameter a fallback was a manual check (x = x || 10) which was buggy when 0 or "" was a valid value. Modern default parameters fix this: they are concise, only triggered by undefined, and can even reference earlier parameters or call other functions.
The basic syntax
function greet(name = "friend") {
return "Hello, " + name;
}
console.log(greet()); // Hello, friend
console.log(greet("Ada")); // Hello, AdaThe expression after = is the default value, evaluated when the parameter would otherwise be undefined.
Triggered by `undefined` only
Defaults only fire when the parameter is exactly undefined — either because the caller omitted it or passed undefined explicitly. Any other value, including null, 0, "" and false, is kept as-is.
function show(value = "default") {
console.log(value);
}
show(); // default
show(undefined); // default
show(null); // null
show(0); // 0
show(""); // (empty string)
show(false); // falseDefaults are evaluated at call time
The default expression runs once per call, not once when the function is defined. That means each call can get a fresh value — important for mutable defaults like arrays.
function pushTo(list = []) {
list.push(1);
return list;
}
console.log(pushTo()); // [1]
console.log(pushTo()); // [1] — a fresh array each time
console.log(pushTo()); // [1]Compare to Python, where mutable defaults are a famous footgun. JavaScript dodges that by re-evaluating the default expression on every call.
Defaults can reference earlier parameters
Each parameter is evaluated left-to-right, and later defaults can use earlier names.
function makeRange(start = 0, end = start + 10, step = 1) {
const result = [];
for (let i = start; i < end; i += step) result.push(i);
return result;
}
console.log(makeRange()); // 0..9
console.log(makeRange(5)); // 5..14
console.log(makeRange(0, 6, 2)); // [0, 2, 4]Trying to reference a later parameter, on the other hand, is a TDZ error:
// function bad(a = b, b = 2) { return a + b; }
// bad(); // ReferenceError: Cannot access 'b' before initializationDefaults can be any expression
A default value is not limited to literals. It can be a function call, an object, or anything else that produces a value.
function newId() {
return Math.random().toString(36).slice(2, 8);
}
function makeUser(name, id = newId(), createdAt = new Date()) {
return { id, name, createdAt };
}
console.log(makeUser("Ada"));
console.log(makeUser("Lin"));Required parameters via defaults
Because defaults are arbitrary expressions, a common trick is to default to a function that throws — making the parameter effectively required.
function required(name) {
throw new Error("Missing required parameter: " + name);
}
function createUser(name = required("name"), email = required("email")) {
return { name, email };
}
createUser("Ada", "ada@example.com"); // ok
// createUser("Ada"); // Error: Missing required parameter: emailDefaults with destructured parameters
Defaults combine nicely with object destructuring to give a function a clean "named arguments" API.
function fetchData({ url, method = "GET", timeout = 5000 } = {}) {
console.log(method, url, "timeout", timeout);
}
fetchData({ url: "/api/users" });
fetchData({ url: "/api/users", method: "POST" });
fetchData(); // {} — destructuring would crash without the `= {}`The = {} at the end protects you when the caller omits the whole argument. Without it, destructuring undefined throws.