参数扩展与收集
- ECMAScript6 新增了扩展操作符,实用它可以非常简洁地操作和组合集合数据,扩展操作符最有用的场景就是函数定义中的参数列表,在这里它可以充分利用这门语言的弱类型及参数长度可变的特点,扩展操作符既可以用于调用函数时传参,也可以用于定义函数参数。
扩展参数
-
在给函数传参时,有时候可能不需要传一个数组,而是要分别传入数组的元素。
-
假设有如下函数定义,它会将所有传入的参数累加起来:
let values = [1, 2, 3, 4]; function getSum() { let sum = 0; for (let i = 0; i < arguments.length; i++) { sum += arguments[i]; } return sum; } -
这个函数希望将所有加数逐个传进来,然后通过迭代 arguments 对象来实现累加。如果不使用扩展操作符,想把定义在这个函数这面的数组拆分,那么就得求助于 apply() 方法了:
console.log(getSum.apply(null, values)); // 10 -
但在 ECMAScript6 中,可以通过扩展操作符极为简单地实现这种操作。对可迭代对象应用扩展操作符,并将其作为一个参数传入,可以将可迭代对象拆分,并将迭代返回的每个值单独传入。
-
比如,实用扩展操作符就可以将前面的例子中的数组像这样直接传给函数:
console.log(getSum(...values)); // 10 -
因为数组的长度已知,所以在使用扩展操作符传参的时候,并不妨碍在其前面或后面再传入其他的值,包括使用扩展操作符传其他参数:
console.log(getSum(-1, ...values)); // 9 console.log(getSum(...values, 5)); //15 console.log(getSum(-1, ...values, 5)); // 14 console.log(getSum(...values, ...[5, 6, 7])); // 28; -
对于 arguments 对象而言,它并不知道扩展操作符的存在,而是按照调用函数时传入的参数接收每一个值:
let values = [1, 2, 3, 4]; function countArguments() { console.log(arguments.length); } console.log(getSum(-1, ...values)); // 5 console.log(getSum(...values, 5)); //5 console.log(getSum(-1, ...values, 5)); // 6 console.log(getSum(...values, ...[5, 6, 7])); // 7; -
arguments 对象只是消费扩展操作符的一种方式。在普通函数和箭头函数中,也可以将扩展操作符命名参数,当然同时也可以使用默认参数:
function getProduct(a, b, c = 1) { return a * b * c; } let getSum = (a, b, c = 0) => { return a + b + c; }; console.log(getProduct(...[1, 2])); // 2 console.log(getProduct(...[1, 2, 3])): //6 console.log(getSum(...[1, 2])); // 3 console.log(getSum(...[1, 2, 3])): //6
收集参数
-
在构思函数定义时,可以使用扩展操作符把不同长度的独立参数组合为一个数组。这有点类似 arguments 对象的构造机制,只不过收集参数的结果会得到一个 Array 实例。
function getSum(...values) { // 顺序累加values中的所有值 // 初始值总和为0 return values.reduce((x, y) => x + y, 0); } console.log(getSum(1, 2, 3)); // 6 -
收集参数的前面如果还有命名参数,则只会收集其余的参数;如果没有则会得到空数组。因为收集参数的结果可变,所以只能把它作为最后一个参数:
// 不可以 function getProduct(...values, lastValue) { } // 可以 function getProduct(firstValue, ...values) { console.log(values) } getProduct(1); // [] getProduct(1, 2); // [2] -
箭头函数虽然不支持 arguments 对象,但支持收集参数的定义方式,因此也可以实现与使用 arguments 一样的逻辑:
let getSum = (...values) => { return values.reduce((x, y) => x + y, 0); }; console.log(getSum(1, 2, 3)); //6 -
另外,使用收集参数并不影响 arguments 对象,它仍然反映调用时传给函数的参数;
function getSum(...values) { console.log(arguments.length); // 3 console.log(arguments); // [1, 2, 3] console.log(values); // [1, 2, 3] } console.log(getSum(1, 2, 3));