• 【JavaScript进阶之旅 ES6篇 第七章】箭头函数的实质、箭头函数this指向、箭头函数的使用场景


    一、箭头函数的实质跟this指向

    1、返回一个对象

    // 在该箭头函数中我们需要返回一个对象
    (a, b) => {a: 3, b: 4} // 这样你会看到报错
    
    // 我们需要将语句变为表达式(语法块,而不是对象)
    let fn = (a, b) => ({a: 3, b: 4}); // 括号包起来,就不会报错了
    
    // 相当于
    function fn (a, b) {
      return {
        a: 3,
        b: 4
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    2、剩余参数

    function fn(f, l, ...args) {
      console.log(f, l, args);
    }
    
    // 不定参数:rest运算符|拓展运算符|展开运算符(为了替代arguments)
    fn(1, 2, 3, 4, 5, 6);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3、箭头函数的this指向

    箭头函数的this指向根据外层函数或全局函数的作用域来决定

    let obj1 = {
      a: 2
    }
    
    let obj2 = {
      a: 3
    }
    
    function foo() { // 全局函数中的this默认指向window
      return () => {
        console.log(this.a);
      }
    }
    
    const bar = foo.call(obj1); // 显示绑定foo函数中的this指向为obj1
    
    // 箭头函数this指向是根据外层函数作用域来决定的,他的外层this指向obj1
    bar(); // {a: 2}
    bar.call(obj2); // {a: 2}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    function foo() { // 全局函数中的this默认指向window
      return () => {
        console.log(this.a);
      }
    }
    
    const bar = foo(); // 函数中的this指向为window
    
    // 箭头函数this指向是根据外层函数作用域来决定的,他的外层this指向window
    bar(); // undefined
    bar.call(obj2); // undefined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    const p = {
      eat() {
        console.log(this); // 默认指向window
      },
      drink: () => {
        console.log(this); // 默认指向window
      }
    }
    
    // 在调用的时候,隐式的将eat函数里的this指向到了p对象上
    p.eat(); // p {}
    // 在调用的时候,箭头函数不会隐式的将this指向到p对象上,他总是指向外层函数作用域
    p.drink(); // window
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    1. 箭头函数的使用场景
    <button id='btn'>按钮</button>
    
    (function() {
      function Button() {
        this.btn = document.getElementById('btn');
      }
    
      Button.prototype = {
        init() {
          this.bindEvent();
        },
    
        bindEvent() {
          // 在指定点击的回调函数时,该回调函数中的this默认指向绑定他的DOM元素
          this.btn.addEventListener('click', this.btnClick, false);
    
          // 我们需要改变该回调中的this指向为Button实例,才可以拿到他所要的信息 
          this.btn.addEventListener('click', this.btnClick.bind(this), false); // 现在回调函数中的this就指向了Button构造函数
          this.btn.addEventListener('click', (e) => this.btnClick(e), false); // 现在回调函数中的this就指向了Button构造函数
    
        },
    
        btnClick() {
          console.log(this);
        }
      }
    
      new Button().init();
    })();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    箭头函数内部是没有this机制的,this指向是固化的,只能够通过父级作用域来获取this,闭包的this

    function foo() {
      // this -> window
      return () => {
        // 无this
        return () => {
          // 无this
          return () => {
            // 无this
            console.log('id', this.id); // 访问的this是最外层第一个非箭头函数的this
          }
        }
      }
    }
    
    // 将foo()函数的this指向由window修改为{id: 1}
    var f = foo.call({id: 1});
    
    var f1 = f.call({id: 2})()(); // {id: 1}
    var f2 = f().call({id: 3})(); // {id: 1}
    var f3 = f()().call({id: 4}); // {id: 1}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    箭头函数不能作为构造函数来使用:call、apply、bind

    没有arguments对象、用rest运算符替代

    let f = function() {
      console.log(arguments);
    }
    
    let f1 = () => {
      console.log(arguments);
    }
    
    f(); // 空的类数组
    f1(); // arguments is not defined
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    setTimeout(() => {
        console.log(arguments); // 报错 arguments is not defined
    });
    
    f();
    let f = function() {
      // console.log(arguments);
      setTimeout(() => {
        // 产生了闭包
        // 一个函数的执行导致另一个函数的定义 -> 形成闭包:外层的函数是闭包
        console.log(arguments); // 空的类数组
      });
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在generator函数当中yield命令不会生效

    二、箭头函数的使用场景

    1、箭头函数不是所有场景都适用

    • 普通函数实现:
    function insert(value) {
      return {
        into: function(array) {
          return {
            after: function(afterValue) {
              array.splice(array.indexOf(afterValue) + 1, 0, value);
              return array;
            }
          }
        }
      }
    }
    
    console.log(insert(3).into([1, 2, 4]).after(2)); // [1, 2, 3, 4]
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 使用箭头函数后:
    let insert = value => ({
      into: (array) => ({
        after: (afterValue) => {
          array.splice(array.indexOf(afterValue) + 1, 0, value);
          return array;
        }
      })
    });
    
    console.log(insert(3).into([1, 2, 4]).after(2)); // [1, 2, 3, 4]
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    2、箭头函数的使用场景

    适合箭头函数写法

    1. 简单的函数表达式、得出唯一的return的计算值、函数内部没有this的引用、没有递归、没有事件绑定、解绑,用箭头函数的方式重构

    2. 内层函数表达式,需要调用this,var self = this, bind(this), 确保适当的this指向到时候,使用箭头函数

    3. 将类数组转换为数组的时候:var args = Array.prototype.slice.call(arguements)

    // 普通函数:函数实参排序
    function sortNumber () {
      return Array.prototype.slice.call(arguments).sort(function(a, b) {
        return a - b;
      });
    }
    
    // 箭头函数:函数实参排序
    const sortNumber = (...args) => args.sort((a, b) => a - b);
    
    console.log(sortNumber(2, 3, 1, 6));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    不适合箭头函数写法

    1. 表达式、函数声明、执行语句情况多的时候 ,还需要用到递归、需要引用函数名、事件绑定、解绑,需要避免使用箭头函数
  • 相关阅读:
    【Matplotlib绘制图像大全】(十):Matplotlib使用boxplot()绘制箱线图
    12.WPF动画
    如何使用Jenkins持续集成构建接口自动化测试--配置邮件通知
    数据集笔记:纽约花旗共享单车od数据
    Delphi指针相关学习
    Three.js使用InstancedMesh实现性能优化
    Kettle BIGNUMBER & TIMESTAMP 类型格式处理
    嵌入式中 动态阿拉伯语字符串 转换 LCD显示字符串【感谢建国雄心】
    多线程编程及Thread类
    Vuex
  • 原文地址:https://blog.csdn.net/Lyb__/article/details/125438618