美文网首页
剩余参数(Rest Parameters)

剩余参数(Rest Parameters)

作者: 叱吒红尘 | 来源:发表于2015-11-14 19:39 被阅读0次

ES6中的Rest Parameters语法

在ES6中规定了Rest Parameters语法:

var f = function(a, b, ...theArgs) { 
    ...
}

f(1, 2, 3, 4, 5) // a=1, b=2, theArgs=[3, 4, 5]

请注意f的第三个参数,在声明时以'...'开头。这样在实际调用时,函数的前两个参数分别映射成a、b,从第三个参数开始,这些参数按照顺序映射成名为theArgs的数组。

这样当函数的参数数量不确定时,我们不需要通过arguments对象来确定函数的参数,使函数写起来更加自然。

rest parametersarguments对象有以下主要的区别:

  • rest parameters只包含没有特别命名的函数参数,比如f中的除了a,b以外的函数参数;arguments对象中包含所有的函数参数
  • arguments对象并不是一个真正的array,然而rest parameters却是一个货真价实的Array实例,可以直接使用sort、map、forEach、push、pop等函数
  • arguments拥有其他特殊技能(比如callee property)

更多细节请看:MDN中关于rest parameters的介绍

underscore中模拟Rest Parameters语法

在underscore有这样一个内部函数restArgs,直接看代码:

  var restArgs = function(func, startIndex) {
    startIndex = startIndex == null ? func.length - 1 : +startIndex;
    return function() {
      ...
    }
  };

这个函数可以把一个函数func的参数"改造"成Rest Parameters,如果不传第二个参数startIndex,默认用最后一个参数收集其余参数。比如_.invoke函数

_.invoke = restArgs(function(obj, method, args) {
    var isFunc = _.isFunction(method);
    return _.map(obj, function(value) {
      var func = isFunc ? method : value[method];
      return func == null ? func : func.apply(value, args);
    });
  });

在初始化_.invoke时就使用了restArgs函数,并且没有传startIndex参数。这样匿名函数function(obj, method, args) {...}的第三个参数args就负责来收集"剩余参数"。

_.invoke函数是将obj遍历,每一项执行一个指定方法method,由于method的不确定性,给method传的参数也具有不确定性。用args直接收集成一个数组,直接使用func.apply(value, args)就可以直接调用函数,十分方便。

我们再来看下restArgs函数的源码

  var restArgs = function(func, startIndex) {
    startIndex = startIndex == null ? func.length - 1 : +startIndex;
    return function() {
      var length = Math.max(arguments.length - startIndex, 0);
      var rest = Array(length);
      for (var index = 0; index < length; index++) {
        rest[index] = arguments[index + startIndex];
      }
      switch (startIndex) {
        case 0: return func.call(this, rest);
        case 1: return func.call(this, arguments[0], rest);
        case 2: return func.call(this, arguments[0], arguments[1], rest);
      }
      var args = Array(startIndex + 1);
      for (index = 0; index < startIndex; index++) {
        args[index] = arguments[index];
      }
      args[startIndex] = rest;
      return func.apply(this, args);
    };
  };

其实也很简单,startIndex代表从第几个参数开始当作是剩余参数,第一步首先修正startIndex,如果没有传,startIndex就是undefined,将startIndex修正为func.length - 1 (一个函数的length属性是这个函数在声明时声明的形参个数)

然后从startIndex开始遍历arguments对象,将startIndex之后的参数放入rest数组中。

接下来就可以调用func函数了,当startIndex为0,1,2时,使用了call方法。由于call方法要将参数一个个传入,当startIndex为其他值(可能很大时),作者可能发现一个个写起来很傻,就用了apply函数(真实是为了性能考虑)。

在underscore中,通过_.restArgs = restArgs将这个函数直接输出,我们可以直接使用。在underscore内部有以下函数使用了restArgs初始化:

  • _.invoke
  • _.without
  • _.union
  • _.difference
  • _.zip
  • _.bind
  • _.partial
  • _.bindAll
  • _.delay
  • _.debounce
  • _.pick
  • _.omit

相关文章

网友评论

      本文标题:剩余参数(Rest Parameters)

      本文链接:https://www.haomeiwen.com/subject/fpzqhttx.html