ES6函数扩展(箭头函数)

作者: 贵在随心 | 来源:发表于2018-01-06 16:22 被阅读1822次

    一、函数参数的用法
    1、参数默认值的设置,与ES5 对比
    ES5中设置参数默认值的写法

     function animal(name, type) {
      var name = name || 'yuan';
      var type = type || 'monkey';
      console.log(name, type);
    }
    

    这个写法有个缺陷:参数传递进来的布尔值必须为true,如果传入的值为空字符串或者undefined 等这些转换为false的参数,则会影响结构。所以,ES6为了弥补这个缺陷,做了如下设置:

    function animal(name = 'yuan', type = 'monkey') {
      console.log(name, type);
    }
    

    2、传入参数类型对输出结果的影响

    function animal(name = 'yuan', type = 'monkey') {
      console.log(name, type);
    }
    animal(); // yuan monkey
    animal(name = 'dog');  // dog monkey
    animal(name = 'yuan', undefined); // yuan monkey
    animal(name = 'yuan', null); // yuan null
    animal(false, undefined); // false "monkey"
    animal(0, undefined); // 0 "monkey"
    

    上面代码4中调取函数的方式,只有不传和传入undefined 的会触发默认值,而传入其它值或者null,则不会触发默认值。
    3、注意参数放置位置

    // 错误写法
    function animal(name = 'yuan', type) {
      console.log(name, type);
    }
    // 正确写法
    function animal(name, type = 'monkey') {
      console.log(name, type);
    }
    

    如上,在设置了默认值的参数后,就不需要在设置其他参数了,通常情况下,若有参数为默认值时,一般是放在尾参数位置。
    4、参数默认值与解构赋值默认值的结合使用
    对比下面两种写法

    // 第一种写法,参数默认值为空对象,解构赋值有具体的默认值
    function method1({x = 0, y = 0} = {}) {
      return [x, y];  
    }
    // 第二种写法,参数默认值是一个具体的属性对象,而对象解构赋值没有设置默认值 
    function method2({x, y} = {x: 0, y: 0}) {
      return [x, y];
    }
    // 函数没有参数时
    method1(); // [0, 0]
    method2(); // [0, 0]
    
    // x 和 y 都有值
    method1({x: 2, y: 3}); // [2, 3]
    method2({x: 2, y: 3}); // [2, 3]
    
    // x 有值, y 没有值
    method1({x: 2}); // [2, 0]
    method2({x: 2}); // [2, undefined]
    
    // x 没有值, y 有值
    method1({y: 2}); // [0, 2]
    method2({y: 2}); // [undefined, 2
    
    // x 和 y 都没有值
    method1({});  // [0, 0]
    method2({}); // [undefined, undefined]
    

    5、使用参数默认值对函数length 属性的影响

    (function (a) {}).length // 1
    (function (a = 5) {}).length // 0
    (function (a, b, c = 5) {}).length // 2
    (function(a, ...b) {} ).length // 1
    

    由上面代码可以看出,函数的参数在指定默认值之后,函数的length 属性会失真,返回的length 值,是没有指定默认值的参数的个数,注意这里的length 也不包括rest参数(如第二点介绍)的个数。
    6、注意点
    因函数参数是默认声明的,如果如果用let 或 const 重新声明变量,会报错:

    function animal(name = "yuan") {
      let name = dog;
      console.log(name);
    }
    animal(); // 报错: Uncaught SyntaxError: Identifier 'name' has already been declared
    

    二、rest 参数
    案例 呈现

    // 求和,把结果赋值给 result
    function sum(result, ...values) {
      console.log(values); // [1, 2, 3, 4],这个变量返回的是一个数组
      values.forEach( function(value, index) {
        result += value;
      })
      console.log(result); 
    }
    sum(11, 1, 2, 3, 4,); // 21
    

    如上,rest参数(3个点 + 变量名)表示的是:获取函数多余的参数,且这个变量是一个数组。还有一点要注意的是rest参数必须是尾参数,后面不能加其他的参数,否则会报错:

    // 错误写法
    function sum(res, ...values, another) {
      console.log(values);
    }
    sum(); // 报错:Uncaught SyntaxError: Rest parameter must be last formal parameter
    

    三、name属性
    ES6中增加了函数的name属性

    const animal = function() {};
    animal.name;  // "animal"
    

    Function 构造函数会发的函数实例,name 属性的值为“anonymous”

    (new Function).name; //  "anonymous"
    

    bind 返回的函数,name属性值会加上“bound”前缀

    function animal() {};
    animal.bind({}).name; // "bound animal"
    

    匿名函数的bind 返回的值“bound”

    (function () {}).bind({}).name; //  "bound"
    

    四、箭头函数
    1、定义
    用箭头“=>”来定义函数。
    2、用法
    对比

    // ES5 写法
    var sum = function(a) {
      return a;
    }
    // ES6 写法
    var sum = a => a;
    

    如上代码,在ES6中,第一个a表示函数参数,箭头“=>”后面的 a 表示函数体。
    上述只是针对一个参数和函数体只有一条语句的写法,若函数参数的个数和函数体的语句超过1个要如何表示呢?如下:

    var sum = (a, b) => { return a + b};
    sum(1,4); // 5
    

    如上,若函数的参数个数超过一个时,需要用圆括号“()”来代表参数,函数体的语句条数超过一条时,需要用大括号将它们括起来。
    当函数体中返回的是对象时,我们需要将其用圆括号“()”括起来:

    var person = name => ({ name: 'yuan', type: 'monkey'});
    

    3、使用注意点
    (1)、函数体内的 this 指向,指向的是定义时所在的对象,而不是使用时所在的对象。
    在箭头函数中 this 指向是固定的:

    function foo() {
     setTimeout( () => {
        console.log('id:', this.id)
      }, 100);
    }
    var id = 21;
    foo.call({ id: 42}); // 42
    

    如上输出结果,此处的this 指向并不是全局对象 window,因为在箭头函数中,this 总是指向函数定义生效时所在的对象,所以输出的结果是 42。
    如果还不清楚箭头函数 this 指向的含义,我们可以这样通俗的理解:在JavaScript 中每一个 function 都有一个独立的运行上下文,而箭头函数不是一个普通的 function ,没有自己的运行上下文。所以在箭头函数中写的 this,具体指的是包含这个箭头函数最近的 function 的上下文中的 this,如果没有最近的 function,this 指向的是全局。
    (2)、不能当做构造函数用,即不能使用 new 命令,否则会报错
    (3),、不可以使用arguments 对象,该对象哎函数体内不存在。如果要用,使用 rest 参数代替
    (4)、不能使用 yield 命令,因为箭头函数不能用作Generator 函数
    六、函数的尾调用
    1、定义
    尾调用是函数式编程的一个重要概念,是指某个函数的最后一步调用另一个函数。

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

    函数f 的最后一步是调用函数g,这就是尾调用。
    2、尾递归
    函数调用自身叫做递归,如果尾调用自身就是尾递归。

    function factorial(n) {
      if(n === 1) return 1;
      return n * factorial(n - 1);
    }
    factorial(5); // 120
    

    在ES6 中只要使用尾递归,就不会发生栈溢出,相对节省内存。
    3、尾递归改写
    为了确保最后一步只调用自身,需要对尾递归函数进行改写,把所有用到的内部变量改写成函数的参数。
    使用柯里化函数编程思想,将多参数的函数转换成单参数的形式:

    function curring(fn, n) {
      return function (m) {
        return fn.call(this, m, n);
      }
    }
    
    function tailFactorial(n, total) {
      if(n === 1) return total;
      return tailFactorial(n - 1, n * total);
    }
    const factorial = curring(tailFactorial, 1);
    factorial(5); // 120
    

    采用ES6的函数默认值改写:

    function factorial(n, total = 1) {
      if(n === 1) return total;
      return factorial(n - 1, n * total);
    }
    factorial(5); // 120
    

    在尾调用优化时,循环是可以用递归代替的,而一旦使用递归,就最好使用尾递归。
    五、总结
    1、本章需要掌握ES6中函数的表示方式,以及 rest 参数的使用。
    2、本章重点:箭头函数的表示方法,以箭头函数使用的注意事项,特别是箭头函数中 this 的指向问题。

    戳我博客

    章节目录

    1、ES6中啥是块级作用域?运用在哪些地方?
    2、ES6中使用解构赋值能带给我们什么?
    3、ES6字符串扩展增加了哪些?
    4、ES6对正则做了哪些扩展?
    5、ES6数值多了哪些扩展?
    6、ES6函数扩展(箭头函数)
    7、ES6 数组给我们带来哪些操作便利?
    8、ES6 对象扩展
    9、Symbol 数据类型在 ES6 中起什么作用?
    10、Map 和 Set 两数据结构在ES6的作用
    11、ES6 中的Proxy 和 Reflect 到底是什么鬼?
    12、从 Promise 开始踏入异步操作之旅
    13、ES6 迭代器(Iterator)和 for...of循环使用方法
    14、ES6 异步进阶第二步:Generator 函数
    15、JavaScript 异步操作进阶第三步:async 函数
    16、ES6 构造函数语法糖:class 类

    相关文章

      网友评论

        本文标题:ES6函数扩展(箭头函数)

        本文链接:https://www.haomeiwen.com/subject/dazlnxtx.html