10分钟搞懂 this 指向

748 阅读2分钟

this 指向非常简单,10分钟就能搞懂!

作用

this 常用于在代码执行的环境中快速指向某个对象,从而进行一些数据相关的便捷操作

分析

浏览器环境中

1. 全局作用域下

this 默认指向 window 对象

console.log(this) // window


function sayThis() {
  console.log(this) // window
}
sayThis()


function aa() {
  console.log(this) //window
  bb()
}

function bb() {
  console.log(this) //window
}

function cc() {
  console.log(this) // window
}

aa()
2. 隐式绑定

this 指向调用者

const person = {
  sayThis: function() {
    console.log(this) // person
  }
}

person.sayThis()

再来看 隐式绑定 的另外一种情况

function sayThis() {
  console.log(this)
}

const personA = {
  sayThis
}

const personB = {
  sayThis
}

personA.sayThis() // this -> personA
personB.sayThis() // this -> personB

说的直白一点,谁离我最近并调用了我,我内部的 this 就指向谁

3. 显示绑定

利用 applycallbind 可以将 this 指向更改为被显示绑定的那个对象

function sayThis() {
  console.log(this)
}

const personA = {}

const personB = {}

sayThis.apply(personA) // this -> personA
sayThis.call(personA) // this -> personA

sayThis.apply(personB) // this -> personB
sayThis.call(personB) // this -> personB

隐式绑定 的例子区别在于:我当前对象上没有任何方法可以去访问 this ,但是我可以通过 显示绑定 去借用别人的方法来访问 this,此时 this 指向会更改为显示绑定的那个对象

4. 实例化

构造函数中 this 指向被实例化的那个对象

function Person() {
  console.log(this) // p
}

const p = new Person()
5. 箭头函数

箭头函数内部默认 没有绑定 this

当你尝试在箭头函数中去访问 this 时,如果当前环境中没有 this,会根据其所在的上下文去查找最近可用的 this

const sayThis = () => {
  console.log(this) // window
}

sayThis()

sayThis() 中默认没有 this ,但距离它最近的 this 也就是 全局作用域 中的 this,因此打印 window

const person = {
  sayThis: function() {
    console.log(this) // person
    setTimeout(function() {
      console.log(this) // window
    }) 
  }
}

person.sayThis()

需要注意的是 setTimeout 中的回调仍然是一个普通函数,因此 this 默认指向 window,如果要在其中访问到 person 对象,通常我们会声明一个变量用于保存 this 的值

const person = {
  sayThis: function() {
    console.log(this) // person
    const _this = this
    setTimeout(function() {
      console.log(_this) // person
    }) 
  }
}

person.sayThis()

或者利用箭头函数本身不绑定 this 但会根据上下来查找的特性将其改造

const person = {
  name: 'person',
  sayThis: function() {
    console.log(this) // person
    setTimeout(() => {
      console.log(this) // person
    }) 
  }
}

person.sayThis()

这里的 sayThis() 可不能更改为箭头函数,否则两个箭头函数都没有绑定 this 指向,最终会打印 window

顺带一提,在 es6 中, sayThis:function(){} 通常会简写为 sayThis(){},后者作为前者的增强写法(语法糖形式),默认是存在 this 绑定的,这一点需要和箭头函数区别开来