• ES6新语法之---扩展(spread)/收集(rest)运算符、默认参数值(3)


    这节学习ES6中的spread/rest(展开或收集运算符)及默认参数值。

    第一部分:扩展运算符(spread)

        场景使用在数组之前

      作用:将一个数组转为用逗号分隔的参数序列

      举例1:数组之前

    function foo(x, y, z){
        console.log(x, y, z)
    }
    foo.appley(null, [1, 2, 3])  //在ES6之前我们这样使用数组作为函数参数调用。 foo(...[
    1, 2, 3])  //此处...[1, 2, 3]就被展开为用逗号隔开的1, 2, 3参数序列

      当运算符"..."用在数组之前时,数组会被转为用逗号分隔的参数序列。

      举例2:替代apply()方法

    // ES5的 写法
    var arr1 = [0, 1, 2];
    var arr2 = [3, 4, 5];
    Array.prototype.push.apply(arr1, arr2);  //push方法参数不能为数组,ES5需要借助apply()方法实现。
    
    // ES6 的写法
    let arr1 = [0, 1, 2];
    let arr2 = [3, 4, 5];
    arr1.push(...arr2);              //ES6中借助扩展运算符直接将数组转为了参数序列。

      举例3:替代数组的concat()方法

    let a = [2, 3, 4]
    let b = [1, ...a, 5]    //此处a数组被展开为2, 3, 4
    console.log(b)          //结果为[1, 2, 3, 4, 5]

      上面的用法基本上替代了concat(..),这里的行为就像[1].concat(a, [5])

      注意:扩展运算符后如果是空数组不会产生任何效果

    [...[], 1]
    // [1]

    第二部分:收集运算符(rest)

      作用:收集剩余的参数转为一个数组。

      场景:在函数参数之前使用。

      举例1:函数参数之前

    function foo(x, y, ...z){   //z表示把剩余的参数收集到一起组成一个名叫z的数组。
        console.log(x, y, z)
    }
    foo(1, 2, 3, 4, 5)          //x赋值1,y赋值2,z中赋值[3, 4, 5]数组

      上例中参数z之前的'...'作为rest使用。

      举例2:解构赋值

    const [first, ...rest] = [1, 2, 3, 4, 5];  //此处'...'作为rest收集运算符使用
    first // 1
    rest  // [2, 3, 4, 5]
    
    const [first, ...rest] = [];
    first // undefined
    rest  // []
    
    const [first, ...rest] = ["foo"];
    first  // "foo"
    rest   // []

    总结:如何判断ES6中的运算符是扩展运算符(spread)还是收集运算符(rest),主要取决于其作用的位置

        1.数组之前,作为扩展运算符使用,将数组转为逗号分隔的参数序列。

        2.函数形参中,收集传入的参数为数组。

        3.解构赋值中,收集对应的数据为数组。

    第三部分:默认参数值

    1.ES6之前默认参数值实现

      在函数实现中我们经常需要设定函数参数默认值,以往的实现方式:

      例1:参数默认值设置

    function foo(x, y){
        x = x || 11;
        y = y || 31;
        console.log(x + y);
    }
    foo();          //42
    foo(5, 6);      //11
    foo(5);         //36
    foo(null, 6);   //17

      这种方式设置默认值很有用,但同时也存在风险,如果传入的参数刚好被认为是false的值,那么结果就会出人意料

      比如:foo(0, 42)  结果是53并非我们想要的42,这里0转为boolean为假,所以x || 11结果为11,而非传入的参数0。

      要修正这个问题,那么就需要增加更多的检查,比如下面这样:

      例2:这里限制了参数是除undefined之外的所有值

    function foo(x, y){
        x = (x !== undefined) ? x : 11;     //x !== undefined表示x参数确实传入了。
        y = (y !== undefined) ? y : 31;
        console.log(x + y);
    }
    foo(0, 42);     //42
    foo(undefined, 6);      //17

      这意味着除undefined之外的所有值都可以直接传入,并正确取值。但是这里还是存在问题,如果用户希望传入的值本身就是undefined呢?接着看

      例3:对传入的参数值本身没有限制

            function foo(x, y) {
                x = (0 in arguments) ? x : 11;  //这里我们只判断参数是否有传入,我们不关心值本身是什么。
                y = (1 in arguments) ? y : 31;
                console.log(x + y);
            }
            foo(5); //36
            foo(5, undefined); //NaN    

      这里foo(5, undefined)结果为NaN,当然这不是我们期望的结果。

      注意:JavaScript设计原则--->undefined意味着缺失,也就是说undefined和缺失无法区别,对于函数参数也是这样。

      为了避免例1,例2,例3中存在的问题,ES6中为我们提供了默认参数值的语法,改进了'undefined'缺失参数赋默认值的流程。

    2.ES6默认参数值

      情景1:参数默认值为具体指定值

            function foo(x = 11, y = 31) {
                console.log(x + y)
            }
            foo()               //42
            foo(5, 6)           //11
            foo(0, 42)          //42
    
            foo(5)              //36
            foo(5, undefined)   //36    丢了undefined
            foo(5, null)        //5     null被强制转为0
            foo(undefined, 6)   //17    丢了undefined
            foo(null, 6)        //6     null被强制转为0

      此处函数声明中的x = 11类似x != undefined ? x : 11。如果传入undefined就表示此参数未传入,使用默认值。

      情景2:默认值为表达式

        函数默认值不仅可以是像31的简单值,也可以是任意合法表达式,甚至是函数调用

            function bar(val) {
                console.log("bar called!");
                return y + val;
            }
            function foo(x = y + 3, z = bar(x)) {
                console.log(x, z)
            }
            var y = 5;
            foo();                  // "bar called"
                                    // 8 13
            foo(10);                // "bar called"
                                    // 10 15
            y = 6;
            foo(undefined, 10);     // 9 10

        上例中默认值表达式是惰性求值的,只在需要时运行 --->也就是参数值省略或为undefined时。

        注意:函数声明中形式参数是在它们自己的作用域中(就是函数声明包裹(...)中),而不是在函数体作用域中。这意味默认表达式中的标识符引用首先匹配形式参数作用域,然后才会搜索外层作用域

        举例:

            var w = 1, z = 2;
            function foo(x = w + 1, y = x + 1, z = z + 1) {
                console.log(x, y, z)
            }
            foo()   //ReferenceError: z is not defined    

        x = w + 1,首先在形参列表作用域中寻找w,没有找到,所以使用外层作用域的w。y = x + 1中在形参列表作用域中找到了x。z = z + 1中在形参列表作用域中并未声明z变量,外层作用域中也未声明。最后报错"ReferenceError: z is not defined"。

        

  • 相关阅读:
    poj 2417 Discrete Logging
    洛谷 P2886 [USACO07NOV]牛继电器Cow Relays
    bzoj 3232 圈地游戏——0/1分数规划(或网络流)
    bzoj 4753 [Jsoi2016]最佳团体——0/1分数规划
    bzoj 5281 [Usaco2018 Open]Talent Show——0/1分数规划
    CF 949D Curfew——贪心(思路!!!)
    bzoj 3872 [Poi2014]Ant colony——二分答案
    bzoj 1731 [Usaco2005 dec]Layout 排队布局——差分约束
    洛谷 1344 [USACO4.4]追查坏牛奶Pollutant Control——最大流
    洛谷 1262 间谍网络——缩点+拓扑
  • 原文地址:https://www.cnblogs.com/diweikang/p/8976854.html
Copyright © 2020-2023  润新知