Skip to content

this

this 表示“当前函数在这次调用里绑定到哪个对象”。它不是在定义时决定的,而是主要由调用方式决定。

先记住一句话

判断 this 时,先不要看函数写在哪里,先看它是怎么被调用的。

默认绑定

函数被独立调用时,会走默认绑定。

js
function foo() {
  console.log(this)
}

foo()

在浏览器非严格模式下,这通常是 window;在严格模式下则是 undefined

所以不要简单记成“独立调用一定是 window”,要记得环境和模式会影响结果。

隐式绑定

如果函数是通过对象调用的,this 通常指向调用它的那个对象。

js
const user = {
  name: 'Lee',
  sayHi() {
    console.log(this.name)
  },
}

user.sayHi() // 'Lee'

这里真正决定 this 的,是调用点 user.sayHi()

隐式绑定很容易丢

js
const user = {
  name: 'Lee',
  sayHi() {
    console.log(this.name)
  },
}

const fn = user.sayHi
fn()

一旦函数被单独取出来再调用,就不再是“对象方法调用”了,原来的隐式绑定也就丢了。

显式绑定

可以通过 callapplybind 人为指定 this

js
function sayHi() {
  console.log(this.name)
}

const user = { name: 'Lee' }

sayHi.call(user)
sayHi.apply(user)

区别可以简单记成:

  • call:立即调用,参数逐个传
  • apply:立即调用,参数数组传
  • bind:不立即调用,返回一个绑定后的新函数
js
const bound = sayHi.bind(user)
bound()

new 绑定

函数通过 new 调用时,this 会绑定到新创建的实例对象上。

js
function User(name) {
  this.name = name
}

const user = new User('Lee')
console.log(user.name) // 'Lee'

可以把它理解成:构造函数里的 this 就是“这次要创建出来的实例”。

箭头函数没有自己的 this

箭头函数不按上面的规则独立绑定 this,它会直接使用外层作用域的 this

js
const user = {
  name: 'Lee',
  sayHi() {
    const inner = () => {
      console.log(this.name)
    }

    inner()
  },
}

user.sayHi() // 'Lee'

所以箭头函数更适合“继承外层 this”,而不是拿来做需要动态 this 的方法。

对象字面量里直接写箭头函数要小心

js
const user = {
  name: 'Lee',
  sayHi: () => {
    console.log(this.name)
  },
}

这里的箭头函数不会把 this 指向 user,因为它没有自己的 this

这也是一个高频误区。

常见场景

事件处理

普通函数作为事件回调时,很多场景下 this 会指向当前触发事件的元素。

定时器 / 回调传递

方法一旦被直接传入回调,常常会丢失原有的对象绑定:

js
const user = {
  name: 'Lee',
  sayHi() {
    console.log(this.name)
  },
}

setTimeout(user.sayHi, 1000)

这类场景通常需要:

  • bind
  • 包一层函数
  • 或改用箭头函数保留外层上下文

一个简单的判断顺序

遇到 this 时,可以按这个顺序想:

  1. 是不是箭头函数
  2. 是不是 new 调用
  3. 是不是 call / apply / bind
  4. 是不是对象方法调用
  5. 否则就看默认绑定

使用建议

  • 判断 this 时,先找调用点,不要先找定义位置。
  • 对象方法被单独传递时,要优先警惕 this 丢失。
  • 需要动态 this 时,用普通函数;需要继承外层 this 时,用箭头函数。
  • 在现代模块和严格模式代码里,不要依赖“默认绑定到全局对象”这种历史行为。

基于 MIT 许可发布