3

关于箭头函数里的this

先说总结:

  • 箭头函数没有自己的this、arguments,箭头函数里的this用的是parent作用域的this
  • 箭头函数里的this是词法作用域,是由代码结构决定的,跟在哪里调用无关,与箭头函数在代码里的位置有关
  • 确定箭头函数里this的指向,可以静态分析代码结构,一直往上找function,如果有,就是最近的function里的this,如果到最外层都没有,就是window
  • 箭头函数的this,一旦确定后是不可更改的

记住,箭头函数里的this是可以静态分析的,但是函数里的this又完全不一样了


下面开始正文

箭头函数没有自己的this、arguments,箭头函数里的this用的是parent作用域的this

廖雪峰的文章说,箭头函数里的this是词法作用域

那么就是由代码结构决定的,跟在哪里调用无关,事实证明也是这样的。

箭头函数出现的位置有两种:

  • 在对象里
  • 在函数里
箭头函数在对象里
var obj = {
    param: 123,
    ff : () => console.log(this), // window, strict模式下是undefined
}

因为箭头函数没有自己的this,会去找parent的this,但是对象不构成单独的作用域,没有词法作用域,所以继续往上找parent,就找到了全局作用域。

通过babel编译,发现直接就把this替换成了undefined

// bebal编译后的结果
// void 0就是undefined
"use strict";

var _this = void 0;

var obj = {
  param: 123,
  ff: function ff() {
    return console.log(_this);
  } 

};
箭头函数在函数里
function test () {
    let param = 5656;
    let ff = () => console.log(this);
}

箭头函数的this是词法作用域,词法作用域是跟代码结构相关的,那么是可以静态分析的。

因为是词法作用域,那么箭头函数里的this跟在哪里调用无关,与箭头函数在代码里的位置有关

我们分析一下,箭头函数没有自己的this,会找parent的this,它的parent的是test函数,函数是有作用域的,有词法作用域,所以test里的this就是箭头函数的this。

也就是箭头函数里的this,通过静态分析,会一直往上找function,找到了,就用最近的function里的this,找不到,就用window

通过babel编译一下,发现箭头函数的this即是test函数里的this:

"use strict";

function test() {
  var _this = this;

  var param = 5656;

  var ff = function ff() {
    return console.log(_this); // 这里的this取的是test函数的this
  };
}

因为箭头函数和test函数的this是一样的,那么如果test函数里的this变化了,那么箭头函数的this也会跟着变化。比如看这个例子:

let obj = {
  param: 123,
  ff: function () {
   let rr = () => console.log(this);
   rr();
  }
}
obj.ff(); // obj , 因为这时ff函数里的this是obj对象
let tt = obj.ff;
tt();  // window ,因为这时ff函数里的this是全局对象

这个通过babel编译后的结果是:

"use strict";

var obj = {
  param: 123,
  ff: function ff() {
    var _this = this;

    var rr = function rr() {
      return console.log(_this);
    };

    rr();
  }
};
obj.ff();
var tt = obj.ff;
tt();
注意,箭头函数的this,一旦确定后是不可更改的

这句的理解是:箭头函数的this一旦确定,就不能更改了,典型的如在setTimeout函数里用箭头函数。要区分上面的情况,箭头函数rr的this取的是ff函数的this,但是ff函数的this是没有确定的,运行起来后ff函数的this才确定。

function test () {
    return () => console.log(this);
}
let obj = {
    aa: 123,
}

let rr = test.call(obj);

setTimeout(rr,1000); // obj ,而不是window   因为箭头函数rr的this已经确定了,后面不能更改

多层嵌套的情况

let obj = {
    ff1: function () {
        let obj2 = {
            ff2:  () => console.log(this),
            obj3: new Object(() => console.log(this))
        };
        return obj2;
    },
    fun1: function (){
         return function fun2(){
            return function fun3(){
               return ()  => console.log(this);
            }
        }
    }
}
obj.ff1().ff2(); // obj, 取的ff1的this
obj.fun1()()()(); // window,取的fun3的this,由于嵌套函数的this不能继承,所以是window

箭头函数ff2里的this,向上找parent,obj2是对象没有作用域,继续向上,找到ff1函数,于是箭头函数ff2的this就是取ff1函数的this。obj3的new Object()的传参是箭头函数,里面的this适用的规则也一样,也是一直向上找parent,最后是ff1函数的this,看babel的转换的代码就知道了。

"use strict";

var obj = {
  ff1: function ff1() {
    var _this = this;

    var obj2 = {
      ff2: function ff2() {
        return console.log(_this);
      },
      obj3: new Object(function () {
        return console.log(_this); // 取的是ff1的this
      })
    };
    return obj2;
  },
  fun1: function fun1() {
    return function fun2() {
      return function fun3() {
        var _this2 = this;

        return function () {
          return console.log(_this2);
        };
      };
    };
  }
};
obj.ff1().ff2(); // obj, 取的ff1的this

obj.fun1()()()(); //

总结

  • 箭头函数没有自己的this、arguments,箭头函数里的this用的是parent作用域的this
  • 箭头函数里的this是词法作用域,是由代码结构决定的,跟在哪里调用无关,与箭头函数在代码里的位置有关
  • 确定箭头函数里this的指向,是静态分析代码结构,一直往上找function,如果有,就是最近的function里的this,如果到最外层都没有,就是window
  • 箭头函数的this,一旦确定后是不可更改的

记住,箭头函数里的this是可以静态分析的,但是函数里的this又完全不一样了


小蚂蚁的白菜
19 声望1 粉丝