一文搞定this指针指向问题(前端面试常考)
2020-08-18 本文已影响0人
苦庭
this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this等于window;当函数被作为某个对象的方法直接调用时,this等于那个对象。
特别注意两种特殊情况:
- 匿名函数的执行环境具有全局性,因此匿名函数中的this对象通常指向window对象。
重点来了:
“js中函数的匿名函数调用执行环境具有全局性”这句话真的非常重要,我们要首先理解js是一种浏览器语言,因此当我们直接定义一个函数并调用时,我们其实是省略了window.
这个前缀的,当我们把所有的调用,比如start()
这样一个函数的执行,理解成是window.start()
的全局调用,我们就不会再搞错究竟这个this指向谁了——只要看调用者是谁即可,方法名前面是哪个对象直接调用this就是指向谁。而匿名函数因为没有带名字,所以全都看作是window前缀的!
function a() { console.log(this); }
setTimeout(a, 0);
a是命名函数,在window对象中被定义的,它的调用是在window.setTimeout()
中被调用的,因此setTimeout(a,0)
等价于window.setTimeout(window.a,0)
,因此在运行时a的指针是指向window的。输出应该为[Window]
class A {
a() {console.log(this)}
start() {
setTimeout(this.a,0);
setTimeout(function(){console.log(this);}, 0);
setTimeout(()=>{console.log(this);},0);
this.a(); //同步代码先执行
}
}
let o = new A();
o.start();
同理,这里start是通过o对象(A类的实例)调用的,因此o对象中的箭头函数/默认的this都应该指向o对象,而o对象中的匿名函数/命名函数因为是在window.setTimeout
中作为window对象的回调函数执行,所以指向还是window
。
输出应该为:[A] [Window] [Window] [A]
- setTimeout()的全名是
window.setTimeout()
,因此所有这些window自带的方法中的this指向都是window对象
function a() {
return new Promise(function(resolve){ //如果把左边这个匿名函数写成箭头函数,想想会出现什么。
setTimeout(()=>{console.log(this)},0);
setTimeout(function(){console.log(this);},0); // 该函数的调用永远都是指向window
console.log(this); //因为传入Promise使用的是匿名函数,所以指向window对象
})
}
let o = new a(); //最后输出都是为window对象
如果把匿名函数写成箭头函数,那么this在动态绑定的时候就会自动往上找上下文,直到找到直接调用该箭头函数的那个对象(包括window对象!)。
function a() {
return new Promise((resolve)=>{
setTimeout(()=>{console.log(this)},0);
setTimeout(function(){console.log(this);},0);
console.log(this);
})
}
let o = new a();
将输出:a window a