• ES6系列 (01):箭头函数this指向问题


    this指向本质

    箭头函数this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数。
    箭头函数转成 ES5 的代码如下:

    // ES6
    function foo() {
      setTimeout(() => {
        console.log('id:', this.id);
      }, 100);
    }
    
    // ES5
    function foo() {
      var _this = this;
    
      setTimeout(function () {
        console.log('id:', _this.id);
      }, 100);
    }
    

    this指向实例

    实例1

    下面代码中,setTimeout的参数是一个箭头函数,这个箭头函数的定义生效是在foo函数生成时,而它的真正执行要等到100毫秒后。如果是普通函数,执行时this应该指向全局对象window,这时应该输出21。但是,箭头函数导致this总是指向函数定义生效时所在的对象(本例是{id: 42}),所以输出的是42。

    function foo() {
      console.log(this); // { id: 42 }
      setTimeout(() => {
          //箭头函数体中的 this 对象,是定义函数时的对象,而不是使用函数时的对象。
        console.log('id:', this.id); // 42
      }, 100);
    }
    var id = 21;
    foo.call({ id: 42 });	// id: 42
    

    实例2

    Javascript 没有块级作用域,即对象、ifforwhile不构成单独的作用域【letconst关键字函数除外】,其只有全局作用域和函数作用域,所以函数b()定义时的作用域就是全局作用域

    var obj = {
      a: 10,
      b: () => {
        console.log(this.a); // undefined
        console.log(this); // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
      },
      c: function() {
        console.log(this.a); // 10
        console.log(this); // {a: 10, b: ƒ, c: ƒ}
      }
    }
    obj.b(); 
    obj.c();
    

    实例3

    实例1和实例2的组合加强版

    var obj = {
      a: 10,
      b: () => {
         console.log(this)  // Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
         setTimeout(() => {
            console.log(this.a) // undefined
            console.log(this)// Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
          });
      },
      c: function() {
          console.log(this)  // {a: 10, b: ƒ, c: ƒ}
          setTimeout(() => {
              console.log(this.a)  // 10
              console.log(this)  // {a: 10, b: ƒ, c: ƒ}
          });
      },
      d: function() {
         console.log(this)  // {a: 10, b: ƒ, c: ƒ}
         setTimeout(function(){
            console.log(this.a)  // undefined
            console.log(this)// Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
         });
      }
    }
    obj.b(); 
    obj.c();
    obj.d();
    

    不适用场合

    定义对象的方法,且该方法内部包括this

    const cat = {
      lives: 9,
      jumps: () => {
        this.lives--;
      }
    }
    

    上面代码中,cat.jumps()方法是一个箭头函数,这是错误的。调用cat.jumps()时,如果是普通函数,该方法内部的this指向cat;如果写成上面那样的箭头函数,使得this指向全局对象,因此不会得到预期结果。这是因为对象不构成单独的作用域,导致jumps箭头函数定义时的作用域就是全局作用域。

    注意点

    • 箭头函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
    • 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
    • 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用rest参数代替。
    • 不可以使用yield命令,因此箭头函数不能用作Generator函数。

    参考文档

    阮一峰 函数的扩展

    人间不正经生活手册
  • 相关阅读:
    C++编译器详解(二)常见precompiling 指令介绍
    C++编译器详解(一)
    Music
    jQuery语法
    Freedom DownTime
    A
    Map类
    伤不起:File.toPath() & Paths.get()
    在不同浏览器中空格显示的效果不一致的问题(主要是宽度不一致)
    关于xmlhttp会使用ie的缓存的问题及解决
  • 原文地址:https://www.cnblogs.com/burc/p/13888268.html
Copyright © 2020-2023  润新知