...在一个数组(实际上,是我们将在第三章中讲解的任何的 可迭代 对象)前面被使用时,它就将数组“扩散”为它的个别的值。

    通常你将会在前面所展示的那样的代码段中看到这种用法,它将一个数组扩散为函数调用的一组参数。在这种用法中,...扮演了apply(..)方法的简约语法替代品,在前ES6中我们经常这样使用apply(..)

    1. foo.apply( null, [1,2,3] ); // 1 2 3

    ...也可以在其他上下文环境中被用于扩散/展开一个值,比如在另一个数组声明内部:

    另一种...的用法常见于一种实质上相反的操作;与将值散开不同,...将一组值 收集 到一个数组中。

    1. function foo(x, y, ...z) {
    2. console.log( x, y, z );
    3. }
    4. foo( 1, 2, 3, 4, 5 ); // 1 2 [3,4,5]

    这个代码段中的...z实质上是在说:“将 剩余的 参数值(如果有的话)收集到一个称为z的数组中。” 因为x被赋值为1,而y被赋值为2,所以剩余的参数值,4,和5被收集进了z

    当然,如果你没有任何命名参数,...会收集所有的参数值:

    这种用法最棒的地方是,它为被废弃了很久的arguments数组 —— 实际上它不是一个真正的数组,而是一个类数组对象 —— 提供了一种非常稳健的替代方案。因为args(无论你叫它什么 —— 许多人喜欢叫它r或者rest)是一个真正的数组,我们可以摆脱许多愚蠢的前ES6技巧,我们曾经通过这些技巧尽全力去使arguments变成我们可以视之为数组的东西。

    考虑如下代码:

    1. // 使用新的ES6方式
    2. function foo(...args) {
    3. // `args`已经是一个真正的数组了
    4. // 丢弃`args`中的第一个元素
    5. // 将`args`的所有内容作为参数值传给`console.log(..)`
    6. console.log( ...args );
    7. }
    8. function bar() {
    9. // 将`arguments`转换为一个真正的数组
    10. var args = Array.prototype.slice.call( arguments );
    11. // 在末尾添加一些元素
    12. // 过滤掉所有奇数
    13. args = args.filter( function(v){
    14. return v % 2 == 0;
    15. } );
    16. // 将`args`的所有内容作为参数值传给`foo(..)`
    17. foo.apply( null, args );
    18. }
    19. bar( 0, 1, 2, 3 ); // 2 4

    在函数foo(..)声明中的...args收集参数值,而在console.log(..)调用中的...args将它们扩散开。这个例子很好地展示了...操作符平行但相反的用途。