「这是我参与11月更文挑战的第2天,活动详情查看:2021最后一次更文挑战」
一句话概括
js this指向问题是一个痛点,但理解也不难,核心思想:
this指向并不取决于定义,而是取决于调用
解释
在this定义的地方,沿着作用域向上找,找到最近的一个function(箭头函数除开,因为es6的箭头函数不带有this),看这个function最终是怎样执行的,this的指向就取决于所属function的调用方式,而不是定义。
function的调用一般分以下5种情况
-
作为函数调用
,即:fun()
this指向全局对象,注意严格模式问题(严格模式全局的this指向的是undefined)
在浏览器里全局对象是window,在node里全局对象是Object [global] -
作为方法调用
,即:obj.fun() / obj.bar.fun() / obj['fun']
this指向最终调用这个方法的对象 -
作为构造函数调用
,即:new Foo()
this指向一个新对象foo {}function foo(){ console.log(this) // => foo {} } new foo()
-
特殊调用
,即:fun.call() / fun.apply() / fun.bind()
this指向绑定的第一个参数成员,如果没有传入参数,则指向全局对象 -
找不到所属的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