JS函数怎么实现传入任意数量参数?

3,247 阅读3分钟

「这是我参与11月更文挑战的第7天,活动详情查看:2021最后一次更文挑战

Rest参数...

🎨让我们从最简单的示例开始说起

假如要实现返回两个数之和的函数,可以这样写

function sum(a, b) {
  return a + b;
}

传入两个参数之后,得到了我们预期的结果

sum(1,2) //3

如果要实现三个数,也很简单,直接加一个参数c

function sum(a, b, c) {
  return a + b + c;
}

在已知变量数量,并且数量很少的时候我们当然可以这样做,但是如果参数未知,或者N多参数呢?比如,想要获得1+2+3+4+5+6+7+8+9+10的和。

如果我们传10个参数进去,很明显是一个很不优雅的写法,这时候我们就可以利用Rest 参数(剩余参数)...来处理。

Rest 参数可以通过使用三个点 ... 并在后面跟着包含剩余参数的数组名称,来将它们包含在函数定义中。这些点的字面意思是“将剩余参数收集到一个数组中”。

现在对任意数量的参数求和,我们可以把所有的参数都放到数组 args 中,这样我们就可以不用关心变量的数量了。

function sumAll(...args) { // 数组名为 args
  let sum = 0;

  for (let arg of args) sum += arg;

  return sum;
}
console.log(sumAll(1, 2))
console.log(sumAll(1, 2, 3))
console.log(sumAll(1, 2, 3, 4))

image-20211107183659903

💥Rest 参数必须放到参数列表的末尾

Rest 参数会收集剩余的所有参数,因此下面这种用法没有意义,并且会导致错误:

// arg2 在 ...rest 后面 ,error ❌
function f(arg1, ...rest, arg2) { }

Spread语法

image-20211107183823665

上以上示例可以看到,我们把参数列表(1,2,3,4)传到函数中,在函数中会得到一个数组[1,2,3,4];

📖 如果现在需要做相反的一个操作,该如何实现?

🎨例如,内建函数 Math.max 会返回参数中最大的值:

Math.max(3, 5, 1) ; //5

🍉假如现在有一个数组 [3, 5, 1],那应该怎么样调用 Math.max 方法呢?

如果直接传入数组,可以看到最终结果为NaN。

image-20211107184348061

📖 那怎么办?

首先,我们肯定不可能手动地去一个个的设置参数 Math.max(arg[0], arg[1], arg[2]),因为我们不确定这儿有多少个。

这时候我们就可以利用Spread 语法来处理,它的写法依然是...,但是作用是完全相反的。

image-20211107185004993

Spread 语法除了,把数组展开,使之成为参数列表之外。还可以将字符串转换为字符数组

image-20211107191818816

扩展

Spread语法还可以用来复制一个数组

let arr = [1, 2, 3];
 // 将数组 spread 到参数列表中
 // 然后将结果放到一个新数组
let arrCopy = [...arr];

修改初始的数组不会修改副本(注意,这只指针对属性值为简单类型)

image-20211107192324869

或者复制一个对象

let obj = { a: 1, b: 2, c: 3 };
// 将对象 spread 到参数列表中
// 然后将结果返回到一个新对象
let objCopy = { ...obj }; 

修改初始的对象不会修改副本(注意,这只指针对属性值为简单类型和Object.assign类似)👉 地址

image-20211107192712115

总结

在代码中看到 "..." 时,它要么是 rest 参数,要么就是 spread 语法。

使用场景

  • Rest 参数用于创建可接受任意数量参数的函数。
  • Spread 语法用于将数组传递给通常需要含有许多参数的列表的函数。

区分

  • 如果 ... 出现在函数参数列表的最后,那么它就是 rest 参数,它会把参数列表中剩余的参数收集到一个数组中。
  • 如果 ... 出现在函数调用或类似的表达式中,那它就是 spread 语法,它会把一个数组展开为列表。

参考资料:

Rest parameters and spread syntax


🎨【点赞】【关注】不迷路,更多前端干货等你解锁

往期推荐

👉 超详细的JS映射(Map)总结

👉 你真的了解JavaScript的解构赋值吗?

👉 JS内置日期对象Date的使用指南

👉 函数进阶之递归初识和实例分析