一文搞定this指针指向问题(前端面试常考)

2020-08-18  本文已影响0人  苦庭

this对象是在运行时基于函数的执行环境绑定的:在全局函数中,this等于window;当函数被作为某个对象的方法直接调用时,this等于那个对象。

特别注意两种特殊情况:

  1. 匿名函数的执行环境具有全局性,因此匿名函数中的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]

  1. 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

上一篇 下一篇

猜你喜欢

热点阅读