js中的this动态指向归纳

59 阅读3分钟

归纳为以下情况

  • 全局下单纯的只有函数,内部无论嵌套多少层,this都会链式指向window(例子略)
  • 被对象作为属性的函数,此时通过obj.property来调用某个函数时,this指向该对象
 function a() {
   console.log(this)
   console.log(arguments)
 }
 ​
 const obj = {
   a,
   b() {
     console.log(this)   // 这是 b : function(){}的简写
   }
 }
 ​
 obj.a()  // this为obj
 a(); // this是window
  • 使用new创建的实例,new会创建一个空对象,让this指向空对象,再把原型链指向创建好,返回this,所以调用new + 方法后,返回的this被赋值给接收的实例,此时实例就是函数内的this对象(例子略)
  • 箭头函数this为上级作用域的this
     // 箭头函数没有This Binding,其this就是上一层作用域的this
     (() => {
       console.log(this)
     })()
     // 打印window
 ​
     const obj_ = {
      fun() {
        // 箭头函数没有this指向,this将在上一级作用域寻找
        (() => {
          // 打印obj_
          console.log(this)
        })();

        // 使用function则有具体的指向,非严格模式指向window
        (function() {console.log(this)})()
      }
    }
 ​
     obj_.fun()
     // 打印obj_
  • 使用特定的方法比如Function.prototype.apply/call/bind等方法可以改变this的指向(例子略)
  • 直接把某个方法(不管是不是在对象内的方法)作为全局window的一些宏任务的回调函数,此时this就指向window\
     // 直接作为定时器的回调函数,this指向window
     // 因为此时obj.b这个方法直接作为定时器的异步的回调在其他线程,1秒后放在了宏任务队列里,此后event loop轮询到
     // 才会把其压入调用栈,作为当前的执行上下文,此时,其只充当定时器的回调函数,而不是对象内的某个属性,在上下文中,this指向全局对象
     setTimeout(obj.b, 1000);
 ​
     // 不直接,实际上仍然是在回调函数内部调用了obj.b(),因此this指向obj
     setTimeout(() => {
       obj.b()
     }, 2000);
     
     // 定时器, 直接把某个函数,不管是不是对象内的属性,都会指向window
     setInterval(obj.b, 3000)
  • 把某个方法作为某个元素的事件监听的回调函数,那么此时回调函数的this指向这个元素
     // 基于某个元素的事件监听, 只要把某个函数作为回调, this就会该元素, 如果监听window就指向window
     document.querySelector('h1').addEventListener('click', obj.b)
     document.body.addEventListener('click', obj.b)
     window.addEventListener('click', obj.b)

本质:

方法本质是一个引用类型的变量或者说是一个对象,永远储存在堆里,而this的指向(环境/执行上下文)取决于我们怎么使用这个方法,当前方法在哪个对象下调用,在哪个环境内

当我们在对象内设置一个属性,值为方法的时候,那么这个属性就存放着这个function的堆数据的地址

而我们直接通过对象 .property / ['property'] 来调用的时候,此时方法被obj这个对象作为属性直接调用,所属的环境就是该对象

而作为元素事件监听和一些宏任务比如定时器的回调函数时,对应的任务会在对应的线程运行,判断满足触发条件后,排入Callback queue,被Event loop事件轮询,此后压入call stack调用栈,函数回调,此时this指向被监听的元素或全局对象window,此时函数的身份是:元素对象的事件监听器的触发函数或在全局的定时器的回调函数,无论此时方法是不是对象的属性(仅存放函数的地址)

如有差错且您有时间,请帮忙指正,不胜感谢