7.函数的拓展

函数的扩展

一.函数参数的默认值

1. 基本用法

  1. ES6之前,不能直接为函数的参数设置默认值,只能在函数体内进行判断并给它赋默认值

    //判断y是否存在,不存在则给它默认值 'world'
    function func(x,y){
        y ? y : 'world';
        console.log(x + y);
    }
  2. ES6允许为函数的参数设置默认值,即直接写在参数定义的后面**

    • 注意:
    • 函数的参数是默认声明的,不能使用 let 和 const 再次声明
    • 参数默认值是惰性求值,只有当需要用到的时候,才会重新计算
    function func(x,y = 'world'){
        console.log(x + y);
    }
    func('hello');           //helloworld
    func("hello","");        //hello

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

  1. 参数的默认值可以和解构赋值的默认值结合使用

  2. 思考:下面两种写法,有什么区别

    function m1({x = 0,y = 0} = {}){
        console.log(`[${x},${y}]`)
    }
    
    function m2({x,y} = {x:0,y:0}){
        console.log(`[${x},${y}]`)
    }
    • 第一种写法,函数参数的默认值是空对象,但是,设置了对象解构的默认值
    • 第二种写法,设置了函数参数的默认值,但是没有设置对象解构的默认值
    m1();                //[0,0]
    m2();                //[0,0]
    
    m1({x:3});           //[3,0]
    m2({x:3});           //[3,undefined]
    
    m1({x:3,y:5});       //[3,5]
    m2({x:3,y;5});       //[3,5]
    
    m1({});              //[0,0]
    m2({});              //[undefined,undefined]

3.参数默认值的位置

  1. 看如下示例

    function func(x=0,y){
        console.log(`[${x},${y}]`);
    }
    
    func();                  //[0,undefined]
    func(1);             //[1,undefined]
    func(,3);                //报错
    func(undefined,3);       //[0,3]
  2. 第二个示例

    function func(x,y=0,z){
        console.log(`[${x},${y},${z}]`)
    }
    
    func();                  //[undefined,0,undefined]
    func(1)                  //[1,0,undefined]
    func(1,,2)               //报错
    func(1,undefined,2)      //[1,0,2]
  3. 总结如上两个示例,可以发现

    • 如果非尾部的参数设置默认值,实际上这个参数是没办法省略的,至少得指定undefined,否则报错
    • 当默认参数在最后的位置的时候,可不用指定
  4. 综上所述,拥有默认值的参数,一般放在参数列表的最后面

4.函数的length属性

  1. 指定了参数默认值的情况下,函数的length属性将只返回没有没有默认值的参数个数

    (function func(x,y){}).length;           //2
    (function func(x=0,y){}).length;     //1

5.默认参数的作用域

  1. 一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域,等到初始化结束,作用域就会消失。这种语法行为,在不设置参数默认值的时候,是不会出现的

    • 如下示例:
    var x = 1;
    function foo(x,y=function(){x=2;}){
        var x = 3;
        y();
        console.log(x);
    }
    foo();                   //3
    console.log(x);          //1
    • 示例解析:在以上示例中,函数的参数形成了一个单独的作用域,在作用域内部,声明了一个变量x,声明了变量y,y的默认值为一个函数,这个函数内部的x指向同一个作用域的第一个参数x。在函数内部,又声明了一个x,该变量与参数内部的x不是同一个作用域,所以不是同一个变量,因此执行y后,函数内部的x变量和函数外部的x变量都没有发生变化
    • 如果去掉函数内部的 var 声明,则函数内部的x变量和函数的第一个参数x是同一个变量,所以执行完y()方法之后,内部的x返回2
    var x = 1;
    function foo(x,y=function(){x=2;}){
        x = 3;
        y();
        console.log(x);
    }
    foo();                   //2
    console.log(x);          //1

6. 应用

  • 可以将函数的某些参数的默认值设置为一个抛出异常的函数,当这些参数为undefined的时候,就会抛出异常
  • 将参数的默认值设置为undefined,说明该参数可以被忽略

二.rest参数

  1. ES6引入了rest参数,形式为(...变量名)。用户获取函数的多余参数,这样就不需要使用arguments对象了

    • 注意:rest之后不能有其它参数,否则会报错
    • rest参数就是一个数组,就函数多余的参数放入数组中
    • 函数的length属性,不包含rest参数
    function func(...numbers){
        console.log(numbers);
    }
    func(1,2,3);     //[1,2,3]
    console.log(func.length)     //0

三.严格模式

  1. 从ES5开始,函数内部可以设置严格模式

    function func(){
        'user strict';
        //code...
    }
  2. ES6做了一点修改,规定只要函数参数使用了默认值,解构赋值,或者扩展运算符,那么函数内部就不能设定为严格模式,否则会报错

    function func(x=10){
        'use strict'
        //...报错
    }

四.name属性

  1. 函数的name属性,返回该函数的函数名,这个属性很早就被浏览器支持,但是在ES6中,才将其写入标准

    • 注意:
    • 如果将一个匿名函数赋值给一个变量,ES5的name属性将会返回一个空串,在ES6中,会返回被赋值的变量名
    • 如果将一个拥有名字的函数赋值给一个变量,不论是ES5还是ES6,其name属性会返回该函数原来的名字
    const f = function bar(){}
    f.name;      // bar
    • Function 构造函数返回的实例,name属性值为 anonymous
    (new Function).name          //annoymous

五.箭头函数

1. 基本用法

  • ES6允许使用“箭头”(=>)定义函数
var f = v => v;

//等同于
var f = function(v){
    return v;
}
  • 如果箭头函数不需要参数或者需要多个参数,就可以 使用一个圆括号代表参数部分
var f = () => 5
//等价于
var f = function(){
    return 5;
}

var f = (x,y) => x + y
//等价于
var f = function(x,y){
    return x + y;
}
  • 如果箭头函数直接返回一个对象,必须在对象外面加上圆括号,否则会报错
//报错
let getTempItem = id => {id:id,name:'temp'}

//不报错
let getTempItem = id => ({id:id,name:'temp'})
  • 箭头函数可以和变量解构结合使用
let func = {first,lasst} => first + ',' + last

//等价于
function func({first,lasst}){
    return person.last + "," + person.last;
}
  • 箭头函数可以简化回调函数
  • 箭头函数可以和rest参数一起使用

2. 使用注意点

  1. 函数内的this对象,就是定义时所在的对象,而不是使用时所在的对象

  2. 不可以当做构造函数,也就是说不可以使用new进行实例化,否则报错

  3. 不可以使用arguments对象,但是可以使用rest参数代替

  4. 不可以使用yield命令,因此箭头函数不能用作Generator函数

  5. 箭头函数中的this,详细说明

    • 箭头函数没有自己的this,所以箭头函数的this总是指向定义该箭头函数的那个对象
    • 箭头函数让this的指向固定化
    • 除了this,以下变量在箭头函数中也是不存在的,arguments,super,new.target

    示例说明

    var handle = {
        id:'123456',
        init:function(){
            document.addEventListener('click',event => this.doSomeThing(event.type),false)
        },
        doSomeThing:function(type){
            console.log('Handing' + type + 'for' + this.id)
        }
    };
    

    示例解析:

    • 上面代码中的init函数中使用了箭头函数,这导致箭头函数里面的this,永远指向handler对象,否则,使用this.doSomeThing调用的时候,就会报错

3. 不适用场合

  1. 由于箭头函数把this由动态变为静态,所以在以下场合,不应该使用箭头函数
    • 定义对象的方法
    • 需要动态this的时候

六.尾调用优化

1. 什么是尾调用

  • 在某个函数的最后一步是调用另一个函数
function f(x){
    return g(x);
}
  • 没有按照上例中返回函数调用的,都不算尾调用
//非尾调用示例
function f(x){
    let y = g(x);
    return y;
}

function f(x){
    return g(x) + 1;
}

function f(x){
    g(x);
}

七.函数参数的尾逗号

  1. ES2017允许函数的最后一个参数可以有逗号,此前,这个都是不被允许的

总结

  1. ES6中,可以为函数添加默认值,默认值可以和解构赋值一起使用
    • 函数默认值的位置最好放在函数参数的最后面,否则还是要在参数中使用undefined来使用默认参数,这使得默认参数没有什么意义
    • 使用默认参数的函数,length返回只会返回没有默认值参数的个数
    • 一旦设置了函数的默认参数,参数会形成一个单独的作用域
  2. ES6中新增了rest参数,rest参数可以接受所有未在函数参数列表中声明的参数,还可以代替arguments对象
  3. 使用了参数默认值,解构赋值和扩展运算符的函数,内部都不能指定严格模式,否则报错
  4. 函数的name属性可以返回函数名,将具名函数赋值给变量之后,name属性获取的还是函数的原始名
  5. 箭头函数可以简化函数的书写,但是得注意,箭头函数的this永远指向定义它的外城对象,箭头函数将动态的this变为了固定的

猜你喜欢

转载自www.cnblogs.com/mapengfei247/p/11105062.html