ES6:Rest 参数和参数默认值【转】

Rest 参数

一般,我们须要建立一个可变参数的函数,可变参数是指函数能够接收恣意数目的参数。比方,String.prototype.concat 能够接收任何数目的字符串作为参数。运用 Rest 参数,ES6 为我们供应一种新的体式格局来建立可变参数的函数。
我们来完成一个示例函数 containsAll,用于搜检一个字符串中是不是包括某些子字符串。比方,containsAll(“banana”, “b”, “nan”) 将返回true,containsAll(“banana”, “c”, “nan”) 将返回 false。
下面是传统的完成体式格局:

function containsAll(haystack) {
  for (var i = 1; i < arguments.length; i++) {
    var needle = arguments[i];
    if (haystack.indexOf(needle) === -1) {
      return false;
    }
  }
  return true;
}

该完成用到了 arguments 对象,该对象是一个类数组对象,包括函数被挪用时的实参列表。这段代码恰是我们想要的,但其可读性却不是最优的。函数只要一个形参 haystack,所以不能够一看就知道该函数须要多个参数,并且在遍历 arguments 时,须要特别注重遍历的最先索引为 1 ,而不是罕见的 0,由于 arguments[0] 就是函数定义时的形参 haystack。假如我们想在 haystack 参数之前或以后增加一些参数,我们不能不更新内部的轮回。Rest 参数处理了这些题目,下面是 运用 Rest 参数的完成体式格局:

function containsAll(haystack, ...needles) {
  for (var needle of needles) {
    if (haystack.indexOf(needle) === -1) {
      return false;
    }
  }
  return true;
}

以上两个完成都满足了我们的需求,但后者包括一个特别的 …needles 语法。我们来看看挪用 containsAll(“banana”, “b”, “nan”) 时的细节,参数 haystack 和以往一样,将用函数的第一个实参添补,值为 “banana”,needles 前面的省略号示意它是一个 Rest 参数,盈余的一切实参将被放入一个数组中,并将该数组赋给 needles 遍量。在这个挪用中,needles 的值为 [“b”, “nan”]。然后,就是一般的函数执行了。
只能将函数的末了一个函数作为 Rest 参数,在函数被挪用时,Rest 参数之前的参数都将被一般添补,以外的参数将被放入一个数组中,并将该数组作为 Rest 参数的值,假如没有更多的参数,那末 Rest 参数的值为一个空数组 [],Rest 参数的值永久都不会是 undefined。

完成Rest参数的函数 restArgs

var restArgs = function (func, startIndex) {
    // rest参数从那里最先,假如没有,则默许视函数末了一个参数为rest参数
    // 注重, 函数对象的length属性, 展现了函数的参数个数
    /*
     ex: function add(a,b) {return a+b;}
     console.log(add.length;) // 2
     */
    startIndex = startIndex == null ? func.length - 1 : +startIndex;
    // 返回一个支撑rest参数的函数
    return function () {
        // 校订参数, 以避免涌现负值状况
        var length = Math.max(arguments.length - startIndex, 0);
        // 为rest参数拓荒数组寄存
        var rest = Array(length);
        // 假定参数从2个最先: func(a,b,*rest)
        // 挪用: func(1,2,3,4,5); 现实的挪用是:func.call(this, 1,2, [3,4,5]);
        for (var index = 0; index < length; index++) {
            rest[index] = arguments[index + startIndex];
        }
        // 依据rest参数差别, 分状况挪用函数, 须要注重的是, rest参数老是末了一个参数, 不然会有歧义
        switch (startIndex) {
            case 0:
                // call的参数一个个传
                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);
        }
        // 假如不是上面三种状况, 而是更通用的(应该是作者写着写着发明这个switch case能够越写越长, 就用了apply)
        var args = Array(startIndex + 1);
        // 先拿到前面参数
        for (index = 0; index < startIndex; index++) {
            args[index] = arguments[index];
        }
        // 拼接上盈余参数
        args[startIndex] = rest;
        return func.apply(this, args);
    };
};

参数的默许值

一般,挪用一个函数时,不须要挪用者通报一切能够的参数,那些没有通报的参数都须要一个合理的默许值。JavaScript 对那些没有通报的参数都有一个牢固的默许值 undefined。在 ES6 中,引入了一种新方法来指定恣意参数的默许值。
看下面例子:

function animalSentence(animals2="tigers", animals3="bears") {
    return `Lions and ${animals2} and ${animals3}! Oh my!`;
}

在每一个参数的 = 背面是一个表达式,指定了参数未通报时的默许值。所以,animalSentence() 返回 “Lions and tigers and bears! Oh my!”, animalSentence(“elephants”) 返回 “Lions and elephants and bears! Oh my!”, animalSentence(“elephants”, “whales”) 返回 “Lions and elephants and whales! Oh my!”。
参数默许值须要注重的几个细节:与 Python 不一样的是,参数默许值的表达式是在函数挪用时从左到右盘算的,这意味着表达式能够运用前面已被添补的参数。比方,我们能够将上面的函数变得更风趣一点:

function animalSentenceFancy(animals2="tigers",
    animals3=(animals2 == "bears") ? "sealions" : "bears")
{
  return `Lions and ${animals2} and ${animals3}! Oh my!`;
}

那末,animalSentenceFancy(“bears”) 将返回 “Lions and bears and sealions. Oh my!”。
通报 undefined 等同于没有通报该参数。因而,animalSentence(undefined, “unicorns”) 将返回 “Lions and tigers and unicorns! Oh my!”。假如没有为一个参数指定默许值,那末该参数的默许值为 undefined,所以

function myFunc(a=42, b) {...}

等同于

function myFunc(a=42, b=undefined) {...}

原文链接

    原文作者:mydef
    原文地址: https://segmentfault.com/a/1190000008276042
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞