默认参数仅在传入undefined时生效,null、0等falsy值不触发;对象/数组需用list ?? []避免引用共享;后续参数可引用前面参数,但不可反向;解构默认值需配合参数默认值{}防null报错。
ES6 开始支持函数默认参数,但很多人直接写 function fn(a = []) 就以为万事大吉——其实这在多数场景下是危险的。默认值只在参数为 undefined 时生效,null、false、0、空字符串都不会触发。
undefined,才会用默认值fn() → 触发默认值;fn(null) → 不触发,默认值被忽略写成 a = [] 看似简洁,但若函数被反复调用且内部修改了这个数组,后续调用会拿到已被污染的旧数组。这不是 bug,是 JS 引用传递的自然结果。
function addItem(item, list = []) {
list.push(item);
return list;
}
addItem('a'); // ['a']
addItem('b'); // ['a', 'b'] ← 意外!复用了上一次的数组
正确做法是用工厂函数或短路逻辑确保每次新建:
list = list || [](但会把 false/0 等 falsy 值也转为空数组)list = list === undefined ? [] : list
list = list ?? [](ES2025 空值合并,仅对 null 和 undefined 生效)可以,但有顺序限制:后面的参数默认值能引用前面已声明的参数,反之不行。这是常见报错源头。
function greet(greeting = 'Hi', name = greeting + ', friend') {
return name;
}
greet(); // 'Hi, friend' ✅
function bad(greeting = name, name = 'Alice') { // ReferenceError: Cannot access 'name' before initialization
return greeting;
}
name 在后面定义也不行当函数参数是解构形式(如 { count = 1 } = {}),两层默认值容易混淆:一层是解构的默认值,一层是整个参数的默认值。
function load({ page = 1, size = 10 } = {}) {
console.log(page, size);
}
load(); // 1 10 ✅
load({}); // 1 10 ✅
load({ page: 2 }); // 2 10 ✅
load(null); // TypeError: Cannot destructure property 'page' of 'null' as it is null. ❌
null 或 undefined,必须给整个参数设默认值(如 = {})才能兜底null 传入,得先做
类型检查:function load(opts = {}) { const { page = 1 } = opts; ... }
null 一来就崩undefined 专属替补”。