箭头函数(=>)

  • A+
所属分类:ES 6 JavaScript Web

ES6 允许使用“箭头”(=>)定义函数。

一.箭头函数

1.基本定义

  • ① 简单写法,一个变量一个表达式返回单值
    var f = v => v;
    
    // 等同于
    var f = function (v) {
      return v;
    };
    
  • ② 空参数
    var f = () => 5;
    // 等同于
    var f = function () { return 5 };
    
  • ③ 多参数
        var sum = (num1, num2) => num1 + num2;
    // 等同于
    var sum = function(num1, num2) {
      return num1 + num2;
    };
    
  • ④ 函数体中多条语句,使用return语句返回并使用大括号将函数体包围起来。
    var sum = (num1, num2) => { 
        num1+=1;
        return num1 + num2; }
    
  • ⑤ 函数结构体也可以不返回
    //一 单行不返回使用void关键字标识
    let fn = () => void doesNotReturn();
    // 二 多行语句不使用return
    var sum = (num1, num2) => { 
    num1+=1;
    num1 + num2; }
    
  • ⑥ 如果箭头函数直接返回一个对象,由于大括号被解释为代码块,必须在对象外面加上括号,否则会报错。
    // 报错
    let getTempItem = id => { id: id, name: "Temp" };
    
    // 不报错
    let getTempItem = id => ({ id: id, name: "Temp" });
    

2. 箭头函数与变量解构结合使用

  • 箭头函数可以与变量解构结合使用。
        const full = ({ first, last }) => first + ' ' + last;
    
    // 等同于
    function full(person) {
      return person.first + ' ' + person.last;
    }
    

3. 箭头函数的使用范例

  • 箭头函数使得表达更加简洁。
    const isEven = n => n % 2 === 0;
    const square = n => n * n;
    
  • 简化回调函数
    // 正常函数写法
    [1,2,3].map(function (x) {
      return x * x;
    });
    
    // 箭头函数写法
    [1,2,3].map(x => x * x);
    
    // 正常函数写法
    var result = values.sort(function (a, b) {
      return a - b;
    });
    
    // 箭头函数写法
    var result = values.sort((a, b) => a - b);
    
  • rest 参数与箭头函数结合的例子
    const numbers = (...nums) => nums;
    
    numbers(1, 2, 3, 4, 5)
    // [1,2,3,4,5]
    
    const headAndTail = (head, ...tail) => [head, tail];
    
    headAndTail(1, 2, 3, 4, 5)
    // [1,[2,3,4,5]]
    

二.箭头函数使用注意点

1.对this指向的影响

  • this对象表示当前对象运行的上下文环境,普通函数有自己的作用域,其定义的this指向就是本身的运行环境,若在对象中运行此函数就是指向此对象,若在全局中运行就指向全局对象;而对象不形成作用域,若对象属性直接定义this或者使用箭头函数定义(非普通函数),则指向上级运行环境(大多是顶级对象window)
     const cat = {
        thisDefine: this,//object window
        lives: 9,
        jumps: () => {
          this.lives--;
          alert(this.lives)//NaN
        },
        jumps2: function () {
          this.lives--;
          alert(this.lives)//8
        }
      }
      alert(cat.thisDefine)//object window
      cat.jumps()
      alert(cat.lives)//9
      cat.jumps2()
      alert(cat.lives)//8
    
  • 箭头函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
    //一 call方法使对象具有调用foo和foo2函数的能力
    //二 setTimeout的参数是一个箭头函数,这个箭头函数的定义生效是在foo函数生成时,而它的真正执行要等到 100 毫秒后。如果是普通函数,执行时this应该指向全局对象window,这时应该输出21。但是,箭头函数导致this总是指向函数定义生效时所在的对象(本例是{id: 42}),所以输出的是42。
    //三 箭头函数可以让setTimeout里面的this,绑定定义时所在的作用域,而不是指向运行时所在的作用域。
      var id = 21;
      function foo() {
        setTimeout(() => {
          console.log('id:', this.id);
        }, 100);
      }
    
      function foo2() {
        setTimeout(function(){
          console.log('id:', this.id);
        }, 100);
      }
      foo2.call({ id: 49 });
      //id: 21
      foo.call({ id: 42 });
      // id: 42
    

2.箭头函数不可以当作构造函数

  • 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。

3.箭头函数没有自己的this,指向外层对象的this

  • 箭头函数中this实质:this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数。
    var handler = {
      id: '123456',
    
      init: function() {
        document.addEventListener('click',
          event => this.doSomething(event.type), false);
      },
    
      doSomething: function(type) {
        console.log('Handling ' + type  + ' for ' + this.id);
      }
    };
    
  • 范例
    //下面代码之中,只有一个this,就是函数foo的this,所以t1、t2、t3都输出同样的结果。因为所有的内层函数都是箭头函数,都没有自己的this,它们的this其实都是最外层foo函数的this。
    function foo() {
      return () => {
        return () => {
          return () => {
            console.log('id:', this.id);
          };
        };
      };
    }
    
    var f = foo.call({id: 1});
    
    var t1 = f.call({id: 2})()(); // id: 1
    var t2 = f().call({id: 3})(); // id: 1
    var t3 = f()().call({id: 4}); // id: 1
    

4.箭头函数除了this,以下三个变量在箭头函数之中也是不存在的,指向外层函数的对应变量:argumentssupernew.target

  • 箭头函数内部的变量arguments,其实是函数foo的arguments变量。
    function foo() {
      setTimeout(() => {
        console.log('args:', arguments);
      }, 100);
    }
    
    foo(2, 4, 6, 8)
    // args: [2, 4, 6, 8]
    
  • 由于箭头函数没有自己的this,所以当然也就不能用call()、apply()、bind()这些方法去改变this的指向。
    //箭头函数没有自己的this,所以bind方法无效,内部的this指向外部的this。
    (function() {
      return [
        (() => this.x).bind({ x: 'inner' })()
      ];
    }).call({ x: 'outer' });
    // ['outer']
    

三.不适宜使用箭头函数场景

1.由于箭头函数使得this从“动态”变成“静态”,实质是内部没有this指向,拷贝上级对象this指向

  • 第一个场合是定义对象的方法,且该方法内部包括this
    //因为对象不构成单独的作用域,导致jumps箭头函数定义时的作用域就是全局作用域this指向全局对象。jumps2定义在普通函数中,形成了作用域,this指向cat对象
      const cat = {
        lives: 9,
        jumps: () => {
          this.lives--;
          alert(this.lives)//NaN
        },
        jumps2: function () {
          this.lives--;
          alert(this.lives)//8
        }
      }
      cat.jumps()
      alert(cat.lives)//9
      cat.jumps2()
      alert(cat.lives)//8
    
  • 第二个场合是需要动态this的时候,也不应使用箭头函数。
    //下面代码运行时,点击按钮会报错,因为button的监听函数是一个箭头函数,导致里面的this就是全局对象。如果改成普通函数,this就会动态指向被点击的按钮对象。
    var button = document.getElementById('press');
    button.addEventListener('click', () => {
      this.classList.toggle('on');
    });
    
zhangfeng

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: