一句话概括this指向问题

1,834 阅读2分钟

「这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战

一句话概括

js this指向问题是一个痛点,但理解也不难,核心思想:
this指向并不取决于定义,而是取决于调用

解释

在this定义的地方,沿着作用域向上找,找到最近的一个function(箭头函数除开,因为es6的箭头函数不带有this),看这个function最终是怎样执行的,this的指向就取决于所属function的调用方式,而不是定义。

function的调用一般分以下5种情况

  1. 作为函数调用,即:fun()
    this指向全局对象,注意严格模式问题(严格模式全局的this指向的是undefined)
    在浏览器里全局对象是window,在node里全局对象是Object [global]

  2. 作为方法调用,即:obj.fun() / obj.bar.fun() / obj['fun']
    this指向最终调用这个方法的对象

  3. 作为构造函数调用,即:new Foo()
    this指向一个新对象foo {}

    function foo(){
      console.log(this) // => foo {}
    }
    new foo()
    
  4. 特殊调用,即:fun.call() / fun.apply() / fun.bind()
    this指向绑定的第一个参数成员,如果没有传入参数,则指向全局对象

  5. 找不到所属的function,就是全局对象

掌握这5点总结,能覆盖所有的this指向问题,下面一些测试,你能答对吗?

测试

1、

var length = 10
function fn() {
  console.log(this.length)
}
const obj = {
  length: 5,
  method(fn) {
    fn()
    arguments[0]()
  }
}
obj.method(fn, 1, 2)

浏览器里执行打印10 3
第一个10,this命中情况1:作为函数调用,this指向全局,所以访问挂载到window上的length为10
第二个3,this命中情况2:作为方法调用,this指向arguments对象{ '0': [Function: fn], '1': 1, '2': 2 },所以length打印3

2、

const obj1 = {
  foo(){
    return () => {
      console.log(this)
    }
  }
}
obj1.foo()()

const obj2 = {
  func : () => {
    console.log(this)
  }
}
obj2.func()

第一个打印obj1对象,this命中情况2:作为方法调用,沿this往上找跳过箭头函数找到function foo,foo由obj1调用,则指向obj1
第二个浏览器打印window,this命中情况5:向上找不到function,就指向全局

3、

class Person{
  say = () => {
    console.log(this)
  }
}
const p = new Person()
p.say()

打印实例Person,this命中情况3:作为构造函数调用,class是Function的语法糖,实质是function,this指向实例p