阅读 40

JavaScript中的this指向问题

笼统来说

this指向当前对象,存在于全局对象与函数中

  • 在全局环境下this指向的就是全局对象

    console.log(this)//Window

  • 在函数中,this指向的是调用该函数的对象

       function fn(){
           console.log(this)
       }
       fn()//Window
       let a={fn:fn}
       a.fn()//a
    复制代码

改变该规则的行为

  • 使用严格模式“use strict”

       严格模式下无法再意外创建全局变量,所以所有在全局中定义的函数的this与全局对象解绑,this指向undefined

        "use strict"
       function fn(){
           console.log(this)
       }
       fn()//undefined
复制代码

       但这么解释或许并不是正确的,严格模式下要求函数必须有确定的调用对象,如a.fn(),所以window.fn()便能得到预期的结果,应该说严格模式只是取消了全局环境下的这一默认行为

        "use strict"
       function fn(){
           console.log(this)
       }
       window.fn()//Window
复制代码

  • 使用call,apply,bind命令式的强制锁定函数的this指向

      使用 call与apply返回的都是一个立即执行函数,是一个新的函数

        let a={}
       function fn(){
           console.log(this)
       }
       fn.call(a)//a
复制代码

       bind返回的是改变this指向后的这个新的函数,而不是立即执行,需要注意的是改变this指向后的这个新函数是无法再次修改this指向的

        let a={}
       function fn(){
           console.log(this)
       }
       let b=fn.bind(a)
       b.call(window)//a
复制代码

       new 关键字也会改变this指向,但本质其实就是call,new会创建一个新对象,然后让函数内部的this指向这个新对象,具体请了解new关键字的实现

特殊情况下的this

  • 箭头函数的this指向

       箭头函数没有this, 也可以理解为箭头函数中的this会继承定义函数时的上下文,可以理解为和外层函数指向同一个this

       以我的理解,函数存在作用域,这个函数作用于哪一个对象,那么这个函数作用域里的this就指向这个对象,对于箭头函数来说,他没有自己独立的作用域,他的作用域就是包含他的函数的作用域,如果没有这个函数那么作用域就是全局

       箭头函数也是无法主动修改this指向的

 let a=()=>console.log(this)
      a()//Window 
     let b={a:()=>console.log(this)}
      b.a()//Window
      let c={a:function(){return ()=>console.log(this)}}
      c.a()()//c
      a.call(b)//Window
复制代码

  • 异步情况下的this指向

       下面一段代码中,b.a()中函数a的this指向对象b,但在setInterval的回调函数里this指向Window。那么将回调函数改为箭头函数,发现this指向了对象b,这段代码的本质其实就是每0.5秒调用一次回调函数,若是当做立即执行函数来解释,那么this指向Window就完全说的通,箭头函数下this指向应与setInterval函数相同,但setInterval是立即执行函数,所以应与a()相同。总结而言可以说此种状况下的this指向完全符合原则并不是什么特殊情况

      function a()
      {
          setInterval(() => {
              console.log(this)
          }, 500);
      }
      let b={a}
      b.a()//b

      function a()
      {
          setInterval(function(){console.log(this)}, 500);
      }
      let b={a}
      b.a()//Window
复制代码

       实际上setTimeout与setInterval的this实现过程如下

        function a(){
            (function(){//此处可省略
              return function(){console.log(this)}
                })()//此处可省略
                ()
                }
        let b={a}
        b.a()//Window
复制代码

       于是省略后的代码便是熟悉的代码了

 let a=new Promise(
            function(res){
                console.log(this)//Window
                res()
            }
        ).then(function(){console.log(this)})//Window
复制代码

       在promise中,不管是不是箭头函数,this指向都是Window。实际上,promise只是将一些函数延后调用罢了,函数调用时作用于谁那this就指向谁

       在ajax中,我们需要监听请求的状态,在监听的事件函数里不要用this而直接使用xhr对象,防止浏览器在处理时出错

  • 立即执行函数的this指向

    let a=function(){
        return function(){console.log(this)}
    }
    let b={a}
    b.a()()//window
    
    let a=function(){
        return function(){console.log(this)}()
    }
    let b={a}
    b.a()//window
    复制代码

       好似没有什么不同,若是以后有什么需要补充的地方再来补充