把函数想成一家餐厅的菜单:参数就是客人下单时给的选项。老规矩是客人没说就服务员自己猜(手写 if 判断);现在新规矩是菜单上直接印好"默认配餐"——客人没点的那一项自动上默认的。关键:只有客人真的没给(undefined)才上默认,给了 0、空字符串、false 也算点了单,不会被换掉。这比用 || 兜底安全得多。
以前默认值要在函数体里写一行 if 判断,现在直接写在参数括号里,像菜单上印好。
// 以前:函数里手动判断"客人给没给"
function add(a, b, c) { // 收三个参数
if (c === undefined) c = 10; // 没给就补上 10
return a + b + c; // 三个数相加
}
console.log(add(1, 2)); // 13(c 没给,用了 10)
// 现在:直接写在参数 = 后面,菜单印好默认值
function add(a, b, c = 10) { // c 没传就自动是 10(写在括号里)
return a + b + c; // 不用再手写 if
}
console.log(add(1, 2)); // 13(c 自动用 10)
console.log(add(1, 2, 3)); // 6(传了 3,就用 3)
|| 是个"心软"的服务员:只要客人给的是 0、空串、false,它都当成"没点",硬塞默认值。而参数默认值只认 undefined。
// || 的坑:0、""、false 都是"假值",会被误换成默认值
function f(a, b) { // 普通函数
b = b || 10; // 只要 b 是假值就换成 10
return b; // 把 b 返回
}
console.log(f(1, 0)); // 10(客人明明点了 0,被当成没点!)
// 参数默认值:只在 undefined 时才兜底
function f(a, b = 10) { // 默认值写括号里,只认 undefined
return b; // 直接返回 b
}
console.log(f(1, 0)); // 0(0 是客人真点的,保留)
console.log(f(1, undefined)); // 10(只有 undefined 才触发默认)
如果你以前用 b = b || 10 写兜底,业务里用户传 0 表示"不限制",结果被悄悄换成 10。这种 bug 特别隐蔽——所以参数默认值最大的价值就是:0、""、false 这种"有效但假"的值不会被误伤。
实战里函数经常收一个"配置对象",这时候解构 + 默认值是最稳的组合。
// 以前:进去还得 obj.name 一个个判断
function fn(obj) { // 收一个对象
let name = obj.name || "未知"; // 没名字就写未知
console.log(name); // 打印出来
}
// 现在:参数直接解构,每个属性都能带默认值
function fn({ name = "未知" } = {}) { // 把对象拆成 name,没 name 就"未知";连对象都没传就用 {}
// ^^^^^^^^ 整个参数都没传时,给个空对象兜底
console.log(name); // 直接用拆出来的 name
}
fn({}); // 未知(空对象里没 name)
fn({ name: "大喇叭" }); // 大喇叭(传了就用传的)
fn(); // 未知(连对象都没传,= {} 救了它)
注意 { name = "未知" } = {} 有两层兜底:= {} 是"客人连盘子都没端来时,自己塞个空盘子",name = "未知" 是"盘子里没这道菜时上默认"。两层各管各的,少写任何一层,调用 fn 都会报错。
① 可能在什么地方用:封装可配置的工具函数(如 ajax(url, method = "GET"))、分页函数 getPage(page = 1, size = 10)、组件默认参数、解析接口返回时兜底字段。
② 常见的问题:用 || 导致 0、"" 被覆盖;默认参数写在非最后位置调用时对不上;解构整个对象时漏写 = {},调用不传对象直接报"Cannot destructure property"。
③ 解决思路:要兜底就用参数默认值或 ??,别用 ||;有默认值的参数尽量放最后;解构对象参数一律写成 function fn({ x = 1 } = {}) 双兜底。