this 的指向规则

JavaScript 中 this 的五种绑定规则及优先级

问题

JavaScript 中 this 的指向是什么?有哪些绑定规则?

解答

this 的值在函数调用时确定,取决于函数的调用方式。共有五种绑定规则。

1. 默认绑定

独立函数调用时,this 指向全局对象(严格模式下为 undefined)。

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

foo() // 非严格模式:window / global
      // 严格模式:undefined

2. 隐式绑定

函数作为对象方法调用时,this 指向该对象。

const obj = {
  name: 'Alice',
  sayName() {
    console.log(this.name)
  }
}

obj.sayName() // 'Alice'

// 隐式丢失:将方法赋值给变量后调用
const fn = obj.sayName
fn() // undefined(this 指向全局)

3. 显式绑定

使用 callapplybind 显式指定 this

function greet(greeting) {
  console.log(`${greeting}, ${this.name}`)
}

const person = { name: 'Bob' }

// call:参数逐个传递
greet.call(person, 'Hello') // 'Hello, Bob'

// apply:参数以数组传递
greet.apply(person, ['Hi']) // 'Hi, Bob'

// bind:返回绑定后的新函数
const boundGreet = greet.bind(person)
boundGreet('Hey') // 'Hey, Bob'

4. new 绑定

使用 new 调用构造函数时,this 指向新创建的实例对象。

function Person(name) {
  // this 指向新创建的实例
  this.name = name
}

const p = new Person('Charlie')
console.log(p.name) // 'Charlie'

5. 箭头函数

箭头函数没有自己的 this,继承外层作用域的 this(词法绑定)。

const obj = {
  name: 'David',
  // 普通函数
  sayName() {
    // 箭头函数继承 sayName 的 this
    const inner = () => {
      console.log(this.name)
    }
    inner()
  },
  // 箭头函数作为方法(不推荐)
  arrowMethod: () => {
    console.log(this.name) // undefined,this 指向外层(全局)
  }
}

obj.sayName() // 'David'
obj.arrowMethod() // undefined

优先级

当多种规则同时适用时,按以下优先级判断:

// new 绑定 > 显式绑定 > 隐式绑定 > 默认绑定

function foo(val) {
  this.a = val
}

const obj = {}
const bar = foo.bind(obj)
bar(2)
console.log(obj.a) // 2

// new 可以覆盖 bind
const baz = new bar(3)
console.log(obj.a) // 2(未改变)
console.log(baz.a) // 3(new 优先)

关键点

  • 默认绑定:独立调用指向全局,严格模式为 undefined
  • 隐式绑定:谁调用指向谁,注意隐式丢失问题
  • 显式绑定call/apply 立即执行,bind 返回新函数
  • new 绑定this 指向新创建的实例对象
  • 箭头函数:无自身 this,继承定义时的外层 this
  • 优先级:new > 显式 > 隐式 > 默认