JS 箭头函数的 this

143 阅读2分钟

我之前的错误理解是:

  • 箭头函数的 this 在编译时确定,继承最近一层函数的 this(或者是最后的全局 this)

  • 而大多数情况下,最近一层的函数是非箭头函数,明知它的 this 是在调用时确定的,所以我错误地理解为以定义时的结构为标准(例如对下面的例子,我直接把 this 认为是 obj1.getThisGetter() 调用时的 this)

  • 根据上面的思路,也可以得到一个箭头函数 this 指向的特点是它的 “不变性”

下面是案例,可以先自己做一下,别翻太快,答案就在下面

const obj1 = {
  name: 'obj1',
  getThisGetter() {
    return () => this 
  }
}

const obj2 = {
  name: 'obj2'
}

const thisGetter1 = obj1.getThisGetter()
const thisGetter2 = obj1.getThisGetter.call(obj2)

const this1 = thisGetter1()
const this2 = thisGetter2()

console.log(this1.name)
console.log(this2.name)

// 下面就是答案了!!!

// 不要翻太远!!!

// 最后警告!!!

根据这个错误的思路,可以爽快地得到输出结果是:obj1 obj1,
但实际输出是:obj1 obj2

“不是说 this 在编译时确定吗,怎么会变呢?”

实际上:

  • 箭头函数没有自己的 this,它通过闭包继承外层作用域的 this:
    箭头函数中获取 this 和通过闭包获取其他的外部参数是同一个操作

  • 闭包的词法作用域在编译时确定,但这个作用域的 this 值是在执行时确定的:
    如果外层作用域不执行(例子中的 getThisGetter 不调用),内部箭头函数的 this 就没有意义(定义时)

  • 因此箭头函数的 this 最终取决于外层函数的调用方式(或其他作用域)

所以例子中:

const thisGetter1 = obj1.getThisGetter()
const thisGetter2 = obj1.getThisGetter.call(obj2)

这里 getThisGetter 两次执行的时候产生两个不同的包含箭头函数的上下文,他们是相互独立的,并且各自的 this 在这时候被确定

所以说箭头函数的 this 不是编译时确定的,也是运行时确定的