11-this

58 阅读3分钟

this

JS中的this是什么

this是和执行上下文绑定的,也就是说每个执行上下文都有一个this

执行上下文主要分为三种——全局执行上下文、函数执行上下文、eval执行上下文

所以**this也对应着三种——全局执行上下文的this、函数中的thiseval中的this**

全局执行上下文中的this

全局执行上下文中的this很简单,就是指向window对象

这也是this和作用域链的唯一交点,作用域链的最底端包含了window对象,全局执行上下文中的this也指向window对象

函数执行上下文中的this

我们可以通过三种方式来设置函数执行上下文中的this

通过函数的call方法设置

 let bar = {
   myName : " 极客邦 ",
   test1 : 1
 }
 function foo(){
   this.myName = " 极客时间 "
 }
 foo.call(bar)
 console.log(bar)
 console.log(myName)

在这里,foo函数内部的this已经指向了bar对象,打印bar可以发现,myName属性已经变成极客时间了

全局打印myName,则提示未定义

除了callbindapply也可以设置函数执行上下文中的this

通过对象调用方法设置

 var myObj = {
   name : " 极客时间 ", 
   showThis: function(){
     console.log(this)
   }
 }
 myObj.showThis()

在这里,执行showThis打印出来的this其实是myObj

使用对象来调用内部的一个方法,该方法的this是指向对象本身的

现在再来看一个例子:

 var myObj = {
   name : " 极客时间 ",
   showThis: function(){
     this.name = " 极客邦 "
     console.log(this)
   }
 }
 var foo = myObj.showThis

现在将这个showThis函数赋给一个全局对象,然后调用该对象

这时候会发现this又指向了全局window对象

所以,可以得到一个结论:

在全局环境中调用一个函数,函数内部的 this 指向的是全局变量 window

通过一个对象来调用其内部的一个方法,该方法的执行上下文中的 this 指向对象本身

通过构造函数中设置

 function CreateObj(){
   this.name = " 极客时间 "
 }
 var myObj = new CreateObj()

这段代码中,this的指向应该是新创建出来的myObj

其实在这其中,new关键字做了以下四件事:

  • 首先创建了一个空对象tempObj
  • 接着调用 CreateObj.call 方法,并将 tempObj 作为 call 方法的参数,这样当 CreateObj 的执行上下文创建时,它的 this 就指向了tempObj 对象;
  • 然后执行 CreateObj函数,此时的 CreateObj 函数执行上下文中的 this 指向了 tempObj 对象;
  • 最后返回 tempObj 对象

所以构造函数中的this其实就是新对象本身

this的设计缺陷以及应对方案

嵌套函数中的this不会从外层函数中继承

 var myObj = {
   name : " 极客时间 ", 
   showThis: function(){
     console.log(this)
     function bar(){console.log(this)}
     bar()
   }
 }
 myObj.showThis()

这里函数showThis中的this指向的是myObj对象,而**bar中的this指向的却是全局对象window**

要解决这个问题,我们有两个解决方案:

  • 使用变量self保存this

    利用变量的作用域机制传递给嵌套函数

     var myObj = {
       name : " 极客时间 ", 
       showThis: function(){
         console.log(this)
         var self = this
         function bar(){
           self.name = " 极客邦 "
         }
         bar()
       }
     }
     myObj.showThis()
     console.log(myObj.name)
     console.log(window.name)
    
  • 使用箭头函数

    箭头函数没有自己的执行上下文,所以会继承调用函数中的this

     var myObj = {
       name : " 极客时间 ", 
       showThis: function(){
         console.log(this)
         var bar = ()=>{
           this.name = " 极客邦 "
           console.log(this)
         }
         bar()
       }
     }
     myObj.showThis()
     console.log(myObj.name)
     console.log(window.name)
    

普通函数的this默认指向全局对象window

默认情况下调用一个函数,其执行上下文中的this默认指向全局对象window

这个问题可以通过call方法来显示调用

也可以通过设置JS的严格模式来解决,在严格模式下,默认执行一个函数,这个函数的执行上下文中的this值就是undefiend