小生愛

        /**
            *   函数的扩展
        */

        'use strict';

        /*
            *  函数参数默认值 
        */
        function Point(x=0, y=0){
          let x;
          this.x = x;
          this.y = y;
        };

        let p = new Point(false, false);
        


        // 设置了函数参数的默认值 是个空对象
        // 设置了解构赋值的默认值
        function m1( {x=0, y=0} = {} ){
          console.log(x, y);
        };


        // 设置了函数参数的默认值是个具体对象
        // 没设置解构赋值的默认值
        function m2( {x, y} = {x:0, y:0} ){
          console.log(x, y);
        };

        m1();
        m2();
        m1({x:3, y:4});
        m2({x:3, y:4});
        m1({});
        m2({});




        // 变量z的值先取内部作用域 如果没有值再取外部作用域
        let z = 1;

        function x(y=z){
          console.log(y);
        }

        x();




        /**
            * rest参数
        */
        // ...变量名 用于获取函数的多余参数 是个数组
        function add(...values){
          let sum = 0;
          for(var val of values){
            sum += val;
          }
          console.log(sum, values);
        };

        add(2, 5, 3);




        function add (...values, a) {
          // rest 参数之后不能再有其他参数 否则报错  
        }

        add(2, 5, 3)




        // 扩展运算符 ...
        // 扩展运算符(spread)是三个点(...) 它好比 rest 参数的逆运算 将一个数组转为用逗号分隔的参数序列
        // 参数里的 ...items 是 [1, 2, 3]
        // 函数体内的 ...items 是 1, 2, 3 传进来的原始参数值
        function push(array, ...items){
          array.push(...items);
          console.log(array);
        };

        push([4], 1,2,3);




        function add(x, y){
          console.log(x, y);
        };

        let numbers = [4, 38];
        // ...numbers 把数组转化成逗号分隔的参数序列
        add(...numbers);




        // 合并数组
        let more = [3, 4];
        [1, 2, ...more]




        let arr1 = ['a', 'b'];
        let arr2 = ['c'];
        let arr3 = ['d', 'e'];
        [...arr1, ...arr2, ...arr3];




        // 与解构赋值结合
        // 如果将扩展运算符用于数组赋值 只能放在参数的最后一位 否则会报错
        let list = [1, 2, 3];
        // a = 1; ...rest接受剩余的其他值 并转化成数组
        let [a, ...rest] = list;
        // a=1, rest=[2, 3]
        console.log(a, rest);




        // 扩展运算符将字符串转换成逗号分隔的参数序列
        console.log(...'hello');




        /**
            * 箭头函数
            * 箭头函数 只要写了 {} 需要在里面写return 才可以返回值
        */
        // 等价于下面的写法
        var f = v => v;
        var f = function (v){return v};




        // 多个参数写法
        let f = (num1, num2) => num1 + num2;
        f(1, 2);





        // 箭头函数多余一条语句 如果要返回内容 需要用return
        let fn = v => {
          let a = 1
          v
        }
        // undefined
        log( fn(1) ) 




        

        // 如果要返回对象 并且只有一条语句 外面必须加上大括号
        let fn = v => ({a: 1})
        // {a: 1}
        log( fn() )





        // 箭头函数与变量解构结合使用
        const full = ({first, last}) => first + ' ' + last;
        full({first:1, last:2});




        // 箭头函数和map用法
        let num = [1, 2, 3].map( (x, y, z) => x*x );
        



        // 箭头函数和rest用法
        const numbers = (...nums) => nums;
        numbers(1, 2, 3);




        // 函数体内的this对象 就是定义函数时所在的对象 而不是使用函数时所在的对象
        function foo(){
            // 这里的this指{id:1} 是在执行apply以后才定义了setTimeout的函数体
            setTimeout( ()=>console.log('id : ', this.id), 1000 );
        };

        foo.apply({id:1});




        // 输出3, 0
        // this 是当前实例
        function Timer() {
            this.s1 = 0;
            this.s2 = 0;
            // 箭头函数
            setInterval(() => this.s1++, 1000);
            // 普通函数
            setInterval(function () {
                this.s2++;
            }, 1000);
        };

        let timer = new Timer();

        setTimeout(() => console.log('s1: ', timer.s1), 3100);
        setTimeout(() => console.log('s2: ', timer.s2), 3100);




        // 箭头函数 固定化this指向
        let handler = {
            id : '123',
            init : function (){
                // this通过箭头函数固定指向了handler 点击事件时没有改变this
                document.addEventListener('click', event => this.doSo(event.type), false);
            },
            doSo : function (type){
                console.log(type, this.id);
            }
        };
        handler.init();




        // 箭头函数没有自己的this 所以bind无效 这里输出2
        (function (){
            ( () => this.x ).bind( {x:1} )();
        }).call({x:2});