参数扩展与收集

66 阅读2分钟

参数扩展与收集

  • 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));