ES6--函数的扩展

一、函数参数的默认值

  • ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。
    function method(x,y=10){
        console.log(x, y);
    }
    method(20);//20 10
  • 参数变量x是默认声明的,在函数体中,不能用let或const再次声明,否则会报错。
    function fn(x=10){
        let x=20;
        console.log(x);//SyntaxError: Identifier 'x' has already been declared
    }
    fn();

1. 与解构赋值默认值结合使用

    function fn({x,y,z}){
        console.log(x, y, z);
    }
    fn({x:1,y:2,z:3});//1 2 3

    function foo([x,y=2,z]){
        console.log(x, y, z);
    }
    foo([1,,3]);//1 2 3
    foo([]);//undefined 2 undefined
    foo([1,,]);//1 2 undefined
    foo([2,3,4]);//2 3 4
    foo();//TypeError: undefined is not iterable
    function fetch(url,{body,method="get",headers={}}){
        console.log(method);
    }
    fetch("http://www.baidu.com",{});//get
    fetch("http://www.baidu.com");//TypeError: Cannot destructure property `body` of 'undefined' or 'null'
  • 如果函数fetch的第二个参数是一个对象,就可以为它的三个属性设置默认值。这种写法不能省略第二个参数,如果结合函数参数的默认值,就可以省略第二个参数。这时,就出现了双重默认值。
    function fetch(url,{body,method="get",headers={}}={}){
        console.log(method);
    }
    fetch("http://www.baidu.com",{});//get
    fetch("http://www.baidu.com");//get
  • 函数fetch没有第二个参数时,函数参数的默认值就会生效,然后才是解构赋值的默认值生效,变量method才会取到默认值get。

2. 参数默认值的位置

  • 通常情况下,定义了默认值的参数,应该是函数的尾参数。因为这样比较容易看出来,到底省略了哪些参数。如果非尾部的参数设置默认值,实际上这个参数是没法省略的。
    function f(x=1,y){
        return [x,y];
    }
    console.log(f());//[1, undefined]
    console.log(f(2));//[2, undefined]
    console.log(f(,1));//报错SyntaxError: Unexpected token ,
    console.log(f(undefined, 1));//[1, 1]
    console.log(f(1, null));//[1, null]
    function f(x,y=5,z){
        return [x,y,z];
    }
    console.log(f());//[undefined, 5, undefined]
    console.log(f(1));//[1, 5, undefined]
    //console.log(f(1,,2));//报错SyntaxError: Unexpected token ,
    console.log(f(1,undefined,2));//[1, 5, 2]
    console.log(f(1,null,2));//[1, null, 2]
  • 如果传入undefined,将触发该参数等于默认值,null则没有这个效果。

3. 函数的 length 属性

  • 指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真。
  • 函数里面的length属性返回的是当前函数的形参个数。
    console.log((function(a){}).length);//1
    console.log((function(a=5){}).length);//0
    console.log((function(a,b,c=5){}).length);//2
  • length属性的返回值,等于函数的参数个数减去指定了默认值的参数个数。比如,上面最后一个函数,定义了 3 个参数,其中有一个参数c指定了默认值,因此length属性等于3减去1,最后得到2。
  • length属性的含义是,该函数预期传入的参数个数。某个参数指定默认值以后,预期传入的参数个数就不包括这个参数了。同理,后文的 rest 参数也不会计入length属性。
    function f(...args){
        console.log(args);
    }
    console.log(f.length);//0
  • 如果设置了默认值的参数不是尾参数,那么length属性也不再计入后面的参数了。

4. 函数的作用域

  • 一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。等到初始化结束,这个作用域就会消失
    var x=1;
    function f(x,y=x){
        console.log(y);
    }
    f(2);//2
  • 参数y的默认值等于变量x。调用函数f时,参数形成一个单独的作用域。在这个作用域里面,默认值变量x指向第一个参数x,而不是全局变量x,所以输出是2。
    let x=1;
    function f(y=x){
        let x=2;
        console.log(y);
    }
    f();//1
  • 函数f调用时,参数y = x形成一个单独的作用域。这个作用域里面,变量x本身没有定义,所以指向外层的全局变量x。函数调用时,函数体内部的局部变量x影响不到默认值变量x。
    如果全局变量x不存在,就会报错。
    function f(y=x){
        let x=2;
        console.log(y);
    }
    f();//ReferenceError: x is not defined
    var x=1;
    function f(x=x){

    }
    f();//ReferenceError: Cannot access 'x' before initialization
  • 参数x = x形成一个单独作用域。实际执行的是let x = x,由于暂时性死区的原因,这行代码会报错。
    如果参数的默认值是一个函数,该函数的作用域也遵守这个规则
    let foo='outer';
    function bar(func=()=>foo){
        let foo='inner';
        console.log(func());
    }
    bar();//outer
  • 函数bar的参数func的默认值是一个匿名函数,返回值为变量foo。函数参数形成的单独作用域里面,并没有定义变量foo,所以foo指向外层的全局变量foo,因此输出outer。
    function bar(func=()=>foo){
        let foo='inner';
        console.log(func());
    }
    bar();//ReferenceError: foo is not defined
  • 匿名函数里面的foo指向函数外层,但是函数外层并没有声明变量foo,所以就报错了。
    var x=1;
    function f(x,y=function(){x=2;}){
        var x=3;
        y();
        console.log(x);
    }
    f();//3
    console.log(x);//1
  • 函数f的参数形成一个单独作用域。这个作用域里面,首先声明了变量x,然后声明了变量y,y的默认值是一个匿名函数。这个匿名函数内部的变量x,指向同一个作用域的第一个参数x。函数f内部又声明了一个内部变量x,该变量与第一个参数x由于不是同一个作用域,所以不是同一个变量,因此执行y后,内部变量x和外部全局变量x的值都没变。
  • 如果将var x = 3的var去除,函数f的内部变量x就指向第一个参数x,与匿名函数内部的x是一致的,所以最后输出的就是2,而外层的全局变量x依然不受影响。
    var x=1;
    function f(x,y=function(){x=2;}){
        x=3;
        y();
        console.log(x);
    }
    f();//2
    console.log(x);//1

二、函数的rest 参数

  • 等价于…values,获取函数多余的参数,使用的是扩展运算符。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。这样就不需要使用arguments对象了。
		   function info(...value){
               console.log(arguments);//[1,2,3,4]
               console.log(value);//[1,2,3,4]
               for(let val of value){
                   console.log(val);//1 2 3 4
               }
           }
           info(1,2,3,4);
  • 注:箭头函数中写arguments对象会报错,因为箭头函数特点是上下文this指针保持一致,而window中不含arguments。
  • arguments对象不是数组,而是一个类似数组的对象。所以为了使用数组的方法,必须使用Array.from先将其转为数组。rest 参数就不存在这个问题,它就是一个真正的数组,数组特有的方法都可以使用。
    function push(array,...items){
        items.forEach(function(item){
            array.push(item);
        });
        console.log(array);
    }
    var a=[];
    push(a,1,2,3);//[1, 2, 3]  
  • 注意,rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。
    function f(a,...b,c){}//SyntaxError: Rest parameter must be last formal parameter 
  • 函数的length属性,不包括 rest 参数。
    console.log((function(a){}).length);//1
    console.log((function(...a){}).length);//0
    console.log((function(a,...b){}).length);//1

三、ES6的严格模式

  • 从 ES5 开始,函数内部可以设定为严格模式。
  • 只要函数参数使用了默认值、解构赋值或者扩展运算符,那么函数内部就不能显示设定为严格模式,否则会报错。
    详细的es5严格模式见下方链接
  • https://blog.csdn.net/qq_45806781/article/details/113791150?spm=1001.2014.3001.5501
  • ES6做了一点修改,规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。
  • 这样规定的原因是,函数内部的严格模式,同时适用于函数体和函数参数。但是,函数执行的时候,先执行函数参数,然后再执行函数体。这样就有一个不合理的地方,只有从函数体之中,才能知道参数是否应该以严格模式执行,但是参数却应该先于函数体执行。

四、函数的name属性

  • 函数的name属性,返回该函数的函数名。
			console.log(info.name);//info
  • 如果将一个匿名函数赋值给一个变量,ES5 的name属性,会返回空字符串,而 ES6 的name属性会返回实际的函数名。
    console.log(f.name);//f
    //es5
    console.log(f.name);//
  • 如果将一个具名函数赋值给一个变量,则 ES5 和 ES6 的name属性都返回这个具名函数原本的名字。

五、自己实现map映射方法

           Array.prototype.fakeMap = function(fn,context){
               console.log(context);//undefined
               let arr = this;//this是当前对象数组
               let temp = [];
               for(let i = 0;i<arr.length;i++){
                   let result = fn.call(context,arr[i],i,arr);
                   temp.push(result);
               }
               return temp;
           }
           var st=[1,2,3,4,5];
           var obj=st.fakeMap(function(value,index,array){
               console.log(this);//window
               console.log(value, index, array);//输出值 索引 原数组
               return value*2;
           });
           console.log(obj);//[2, 4, 6, 8, 10];
  • 原型链方法中的this指针指向当前对象。
           function myArray(){

           }
           myArray.prototype.map = function(){
               console.log(this);//当前对象
           }
           let arr = new myArray();
           arr.map();
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

南初️

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值