浅析ES6箭头函数的this绑定是声明时绑定的还是运行时确定的

  ES6都用了这么久了,我们都知道箭头函数没有 this,但是正好昨天做项目的时候纠结了一下这个问题,网上找了几篇排名比较靠前的文章,但都没有完全理解,或者说总觉得文章的说法并不完全正确。所以想要自己去实践一下得到自己的理解。

  先来看看MDN怎么说: 箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this。就这么简单的一句话,其实已经把箭头函数的this指向完全解释清楚了。

一、示例理解

  我们看一下这下面的 3 个示例:

const obj = {
    a: () => {
        console.log(this)
    }
}
obj.a()
// 结果为window,很好理解,例子中只有两个作用域,全局作用域和箭头函数自己的作用域,按照定义,它的作用域链上一层就是window
const obj = {
    a: function () {
        console.log(this)
    }
}
obj.a()
// 结果为 obj,也好理解,obj调用的
const obj = {
    b: this,
    a: {
        c: this
    }
}
obj.b // window
obj.a.c // window

  所以最近的 this 指向就是 window。再看这个示例,箭头函数的 this 不会被 call 之类的影响

var foo = () => {
    console.log(this, this.a)
}
var obj = { a: 2 }
foo.call(obj)  // undefined this为window

  那么再看下面这个例子

function foo() {
    return () => {
        console.log(this.a);
    }
}
var obj1 = { a:2 };
var obj2 = { a:3 };
foo()() // undefined   this为window
foo.call(obj1)() // 2  this为obj1
foo.call(obj2)() // 3  this为obj2

  为什么从这个示例看,好像箭头函数的 this 被 call 影响到了呢?

  实际上是这样的:与传统的函数不同,箭头函数的this不能通过apply,bind,call等方式改变,从定义开始,它的this指向就是确定的,即静态作用域。但是有一点需要注意的是,指向静态不代表值也是静态的。由于它始终指向上一层作用域的this,而上一层作用域只要是函数作用域,this代表的值就可以通过apply,bind,call的方式改变。所以上例中的结果分别是undefined、2、3

二、深入理解

  简单总结一下:

1、箭头函数作为函数的一种形式,对于this的处理和普通函数有所区别,其没有自己的this上下文,也就是说通过bind/call/apply函数方法设置this值时无效的,会被忽略

2、因为箭头函数没有自己的this上下文,那么当它作为对象的方法函数运行时,this并不指向这个对象

3、箭头函数的的函数体中出现的this在运行时绑定到最近的作用域上下文对象

4、你可以认为箭头函数的this和调用者无关,只和其定义时所在的上下文相关

  我们看一下 es6 的箭头函数转换成 es5 是怎样的?实际上它就是在最近的上一层作用域里做了一次this重定向

  他把这个 this 提到了上一层,然后做了一个 this 重定向的操作

  运行 obj.a 箭头函数时,将会查找this绑定的上下文对象:如果obj定义在一个函数体内,那么这个this就绑定到这个函数体对应的this对象上;如果定义在一个全局作用域下,那么就绑定到全局window对象上(浏览器环境下)

  可以看到它就是通过这种 this 重定向的方式去从自己作用域链的上一层去继承this的

function objWrapper(){
    var a=10;
    var obj = {
        foo: () => console.log(this.a)
    };
    obj.foo();
}
objWrapper.call({a:20});//20
objWrapper();//undefined

  所以需要注意的就是指向静态,并不代表值是静态的。

  那么回到标题的问题?箭头函数的 this 是声明时绑定的,还是运行时确定的呢?

  声明时绑定的意思是它要确定到其上一层去做一个 this 重定向的处理。运行时确定是指其上一层的 this 是受运行时调用者影响的,那么箭头函数继承至该 this,自然也会受到影响。

  也就是说:声明时确定继承自谁的 this、运行时真正确定是哪个 this

posted @ 2020-06-10 22:46  古兰精  阅读(1370)  评论(0编辑  收藏  举报