主题
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()一旦函数被单独取出来再调用,就不再是“对象方法调用”了,原来的隐式绑定也就丢了。
显式绑定
可以通过 call、apply、bind 人为指定 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 时,可以按这个顺序想:
- 是不是箭头函数
- 是不是
new调用 - 是不是
call/apply/bind - 是不是对象方法调用
- 否则就看默认绑定
使用建议
- 判断
this时,先找调用点,不要先找定义位置。 - 对象方法被单独传递时,要优先警惕
this丢失。 - 需要动态
this时,用普通函数;需要继承外层this时,用箭头函数。 - 在现代模块和严格模式代码里,不要依赖“默认绑定到全局对象”这种历史行为。
