一句话核心原则
this 永远看函数“怎么调用”,而不是“在哪定义”。
一、判断 this 的完整步骤(通用解法)
当看到一个函数时,按下面顺序判断:
1️⃣ 是箭头函数吗?
2️⃣ 是 new 调用吗?
3️⃣ 是 call / apply / bind 吗?
4️⃣ 是对象调用吗?
5️⃣ 默认调用?
二、五大规则(按优先级)
① 箭头函数(最高优先级)
箭头函数没有自己的 this
它的 this 继承自外层作用域
const obj = {
name: "Tom",
say: () => {
console.log(this.name)
}
}
obj.say()
输出:
undefined
因为箭头函数的 this 不是 obj,而是外层(全局)。
正确写法
const obj = {
name: "Tom",
say() {
console.log(this.name)
}
}
输出:
Tom
② new 调用
new 会创建新对象,并把 this 指向它
function Person(name) {
this.name = name
}
const p = new Person("Tom")
console.log(p.name)
this → 新创建的对象
new 做了什么?
等价于:
const obj = {}
obj.__proto__ = Person.prototype
Person.call(obj)
return obj
③ call / apply / bind
显式绑定优先级高于普通调用
function say() {
console.log(this.name)
}
const obj = { name: "Tom" }
say.call(obj) // Tom
say.apply(obj) // Tom
const fn = say.bind(obj)
fn() // Tom
this → 指向传入的对象
④ 对象调用
谁调用,this 指向谁
const obj = {
name: "Tom",
say() {
console.log(this.name)
}
}
obj.say()
this → obj
⚠ 注意:
const fn = obj.say
fn()
这里是普通调用,不是对象调用。
this → window(或 undefined 严格模式)
⑤ 默认绑定(最容易踩坑)
function say() {
console.log(this)
}
say()
非严格模式:
window
严格模式:
undefined
三、优先级总结(面试高频)
箭头函数
↓
new
↓
call / apply / bind
↓
对象调用
↓
默认绑定
谁优先级高,谁生效。
四、常见面试陷阱
1️⃣ 回调里的 this
const obj = {
name: "Tom",
say() {
setTimeout(function () {
console.log(this.name)
}, 1000)
}
}
obj.say()
输出:
undefined
因为 setTimeout 里的函数是普通函数。
解决方式 1:箭头函数
setTimeout(() => {
console.log(this.name)
})
解决方式 2:bind
setTimeout(function () {
console.log(this.name)
}.bind(this))
2️⃣ 多层对象
const obj = {
name: "A",
foo: {
name: "B",
say() {
console.log(this.name)
}
}
}
obj.foo.say()
this → foo
输出:B
3️⃣ 丢失 this(最常见)
const obj = {
name: "Tom",
say() {
console.log(this.name)
}
}
setTimeout(obj.say, 1000)
this → window
因为本质:
const fn = obj.say
setTimeout(fn)
4️⃣ 链式调用
const obj = {
name: "Tom",
say() {
return function () {
console.log(this.name)
}
}
}
obj.say()()
this → window
五、终极判断口诀
看到 this,问自己三件事:
① 是箭头函数吗?
② 是 new 调用吗?
③ 是谁在点它?
六、面试标准回答
可以这样说:
this 的指向由函数的调用方式决定,而不是定义位置。
判断顺序:
- 箭头函数继承外层 this
- new 绑定到实例
- call/apply/bind 显式绑定
- 对象调用绑定到调用对象
- 默认绑定到 window(严格模式为 undefined)
优先级:箭头函数 > new > 显式绑定 > 隐式绑定 > 默认绑定。
七、高阶一点(你这个水平要知道)
1️⃣ 箭头函数不能被 new
const fn = () => {}
new fn() // 报错
2️⃣ bind 不能被二次修改
function say() {
console.log(this.name)
}
const fn = say.bind({ name: "A" })
fn.call({ name: "B" }) // 仍然是 A
3️⃣ 箭头函数 + new 的优先级
function Person() {
this.say = () => {
console.log(this)
}
}
const p = new Person()
p.say()
this → p
因为箭头函数继承的是构造函数的 this。
八、一句话终极理解
this = 函数执行时的“调用者上下文”
你想往哪个方向深入?