ES6 函数扩展
写了这么多函数,你一定遇到过这些情况:参数不传就报 undefined、想传不确定数量的参数却不会写。
ES6 给函数带来了两个实用升级:参数默认值和 rest 参数(...args)。
参数默认值
为什么需要默认值
看下面这个例子,不传参数时很不友好:
// ES5:不传参数,name 就是 undefined
function greet(name) {
console.log('你好,' + name);
}
greet(); // 你好,undefined
greet('小明'); // 你好,小明
ES6 允许在定义参数时直接写默认值,没传参数时自动用它:
// ES6:参数默认值
function greet(name = '访客') {
console.log('你好,' + name);
}
greet(); // 你好,访客
greet('小明'); // 你好,小明
关键点:
- 只传
undefined时会用默认值;传null不会(null是”故意传空”,会被保留)。 - 有默认值的参数最好放最后,否则调用时容易乱(见下面示例)。
// 示例:默认值放后面,调用才自然
function info(name, age = 18) {
console.log(name + ' ' + age);
}
info('小明'); // 小明 18
info('小红', 20); // 小红 20
// 反例:默认值放前面,想传 age 还得为 name 传 undefined
function bad(age = 18, name) {
// ...
}
bad(undefined, '小红'); // 只能这样调用,别扭
rest 参数(...参数名)
如果函数的参数数量不固定怎么办?ES5 用 arguments,ES6 用 rest 参数更直观。
// ES6:rest 参数收集"剩余的所有实参"为一个数组
function sum(...nums) {
let total = 0;
for (const n of nums) {
total += n;
}
return total;
}
console.log(sum(1, 2)); // 3
console.log(sum(1, 2, 3, 4)); // 10
三个要点:
- rest 参数必须写在参数列表最后,它负责”回收剩余的参数”。
- 没有多余参数时,rest 是空数组
[],不会报错。 - 前面固定的参数照常使用:
// 示例:固定参数 + rest 参数
function log(prefix, ...rest) {
console.log(prefix, rest);
}
log('提示', 1, 2, 3); // 提示 [1, 2, 3]
rest 和 arguments 的区别
| 对比 | arguments(ES5) |
rest 参数(ES6) |
|---|---|---|
| 形态 | 类数组,不能直接用数组方法 | 真正的数组 |
| 是否包含全部参数 | 包含全部 | 只收”剩余”的 |
| 与固定参数次序 | 内部对象,不灵活 | 明确定义,清晰 |
rest 参数更推荐:它就是普通数组,能用 map、filter 等等直接操作。
小提示:这里只介绍 rest 参数的”收集”用法。展开运算符 ...(把数组再还原成一个个参数)写法几乎一样、作用相反,在本系列”运算符扩展”篇正式介绍,方便对比记忆。
组合使用
默认值 + rest 可以一起用,覆盖面更广:
// 示例
function createUser(name = '无名', tags = [], ...others) {
console.log('名字:' + name);
console.log('标签:' + tags);
console.log('其他:' + others);
}
createUser('小明', ['前端'], '男', 99);
// 名字:小明
// 标签:['前端']
// 其他:['男', 99]
常见疑问
默认值可以是任意表达式吗
可以,默认值可以是表达式,甚至可以是函数调用的结果:
// 示例
function getNow() {
return new Date().getFullYear();
}
function logYear(year = getNow()) { // 没传时自动取当前年份
console.log(year);
}
写 null 也能触发默认值吗
不能。只有 undefined 会触发默认值,null 会被原封不动保留。