根据MDN文档及相关博客总结一下this在各种情况下的指向问题。基本规则有三条:
函数中的this指向调用它的对象;
箭头函数的this指向为定义时外部上下文的this指向;
call,bind,apply函数调用的函数this指向为第一个参数。
全局上下文
在全局状态下this指向全局对象,浏览器端指向window,node端指向globalThis
console.log(this===window)//true
函数中的this
对象调用函数,函数中的this指向最近的调用它的对象,函数前没有对象则视为全局对象调用函数
vara=1;varb={a:2,};functionprint(){console.log(this.a);}print()//1指向windowb.x=printb.x();//2指向b
使用call,bind,apply函数调用的函数this指向为第一个参数
apply(obj,args)
vara=1;varb={a:2,};functionprint(x,y){console.log(this.a+x+y);}print.apply(b,[3,5])//10this指向b
call(obj,...args)
vara=1;varb={a:2,};functionprint(x,y){console.log(this.a+x+y);}print.apply(b,3,5)//10this指向b
bind(obj,...args) 使用bind函数绑定过后函数的this将永久被改变,无论调用方式如何,总是指向绑定的对象。已经被bind过的函数不会再bind到其他对象上。
varb={a:2,};varc={a:3,};functionprint(){console.log(this.a);}c.say=print.bind(b);c.say()//2this被绑定到bb.say=c.say.bind(c)b.say()//2第二次bind不会生效
箭头函数中的this
箭头函数没有自己的this,他的this继承自外部函数,指向创建时的外部函数的this。不能够直接改变箭头函数的this(如bind函数等),但可以通过改变外部函数的this指向间接改变箭头函数this指向
在全局创建一个箭头函数
letfn=()=>{console.log(this===window);//true};leta={};fn();a.print=fn;a.print();//truethis始终指向创建时指向的window
对象中创建箭头函数
varobj={bar:function(){varx=(()=>this);returnx;}};varfn=obj.bar();//直接调用fn而不设置this,//通常(即不使用箭头函数的情况)默认为全局对象console.log(fn()===obj);//true//但是注意,如果你只是引用obj的方法,而没有调用它varfn2=obj.bar;//那么调用箭头函数后,this指向window,因为bar的this指向window,箭头函数从bar继承了this。console.log(fn2()()==window);//true
函数作为对象的属性
函数作为对象属性时,this指向仍由调用函数的对象决定
函数在对象的原型链上,概念仍然适用
varo={f:function(){returnthis.a+this.b;}};varp=Object.create(o);//p的原型上有方法fp.a=1;p.b=4;console.log(p.f());//5虽然方法在原型上,但调用者仍然是p
函数作为构造函数
函数作为构造函数调用时,this指向实例化后的对象。
functiona(value){this.value=value;this.fn=function(){console.log(this.value);};}letobj1=newa(10);obj1.fn();//10
谨记:this指向调用函数的对象
事件处理函数的this
addEventListener添加事件处理函数,或者内联事件函数,函数的this指向绑定事件的函数(this===event.currentTarget始终为true),例如给父元素添加click事件监听,点击子元素,this指向父元素,而不是被点击的子元素