rest 直译就是"剩下的"。用 ...args 把调用时没人点名要的实参,全部打包成一个真数组收进来,替代又绕又不是真数组的 arguments。
以前函数里想拿"传进来的所有参数",得用 arguments——它长得像数组(有 length、能按下标取),但其实是"类数组",map/filter/push 这些数组方法一个都用不了。
// 以前:arguments 是"类数组"
function data() { // 没写参数
console.log(arguments); // 用 arguments 收全部实参
}
data("大哥", "二哥", "三哥"); // 传三个
// {0:"大哥",1:"二哥",2:"三哥",length:3} —— 不是真数组!
// 现在:...args 直接给真数组
function data(...args) { // ... 把所有实参打包成真数组
// ^^^^^ 把剩下的全部打包成数组
console.log(args); // 直接打这个真数组
}
data("大哥", "二哥", "三哥"); // 传三个
// ["大哥","二哥","三哥"] ← 真数组,想怎么用怎么用
类数组 = 长得像数组、但 map/filter/push 全不能用,得先 Array.from(arguments) 转一遍。...args 给的是真数组,省了这一步。
参数列表里前面几个是"点名要的",... 永远收"别人挑剩下的"。
// 前两个参数 a、b 先被点名拿走,剩下的全进 rest
function data(a, b, ...rest) { // a、b 点名拿前两个,...rest 收剩下的
// ↑ ↑ ^^^^^^^ 剩下的打包
console.log(rest); // 只打剩下的
}
data("大哥", "二哥", "三哥", "四哥"); // 传四个
// ["三哥","四哥"] ← 前两个被 a、b 拿走,剩下两个进 rest
如果你把 ...rest 写在参数列表中间(比如 function f(a, ...rest, b)),浏览器会直接报错。因为它要收"剩下的",后面不能再有别的参数了——rest 必须永远放最后一位。
// 求一堆数的和(传几个都行)
function sum(...nums) { // ...nums 把所有数收进真数组
let total = 0; // 累加器从 0 开始
for (let n of nums) total += n; // nums 是真数组,直接 for...of
return total; // 返回总和
}
console.log(sum(1, 2, 3, 4)); // 10
// 拼成字符串:rest 是数组,join 直接用
function joinAll(...args) { // 收所有实参成真数组
return args.join(" - "); // 真数组才有 join
}
console.log(joinAll("A", "B", "C")); // 传三个
// A - B - C
// 箭头函数里根本没有 arguments 这个变量 let data = (...args) => console.log(args); // 箭头函数只能用 rest 收参数 // ^^^^^^ 只能用 rest 收参数 data(1, 2, 3); // [1,2,3]
① 可能在什么地方用:写不定参数的工具函数(sum(...nums)、min(...nums))、事件回调里收全部参数、箭头函数里想拿全部参数(因为没有 arguments)。
② 常见的问题:把 ...rest 放中间导致语法报错;把 rest 和 arguments 混用;以为 rest 能拿到"已经点名的参数"。
③ 解决思路:rest 永远放最后;箭头函数里用 ...args 代替 arguments;需要全参数就一个 ...args,需要前几个就点名 + rest 组合。