箭头函数与 this
本教程共 80 篇 · 第 20 篇 · 更新于 2026-08-10 · 约 10 分钟阅读
本节目标:理解箭头函数与普通函数在 this 上的本质区别,学会在 TypeScript 中声明 this 类型,掌握回调中 this 的正确处理方式。
JavaScript 的 this 指向问题是经典的”面试常考题”,也是实际的 bug 来源。TypeScript 提供了两个工具来帮你管好 this:箭头函数和 this 类型声明。
箭头函数不绑定自己的 this
这句话可能是 JavaScript 中最重要的一句话之一:普通函数的 this 取决于如何调用,箭头函数的 this 取决于在哪里定义。
const obj = {
name: "TypeScript",
// 普通函数
greetNormal: function () {
console.log("Hello, " + this.name);
},
// 箭头函数
greetArrow: () => {
console.log("Hello, " + this.name);
},
};
obj.greetNormal(); // "Hello, TypeScript"——this 指向 obj
obj.greetArrow(); // "Hello, undefined"——this 指向外层(全局/模块作用域)
greetArrow 是一个箭头函数,它没有自己的 this,所以 this 从箭头函数定义时的外层作用域继承。在模块顶层定义时,外层就是全局作用域(或者模块作用域),this 是 undefined(strict 模式下)。
再看一个更实用的例子——回调中的 this:
class Timer {
seconds = 0;
// 普通方法——回调中 this 会丢失
startNormal() {
setInterval(function () {
this.seconds++;
// ~~~~ ❌ this 指向全局对象(或 undefined),不是 Timer 实例
}, 1000);
}
// 箭头函数——this 被正确捕获
startArrow() {
setInterval(() => {
this.seconds++;
// ~~~~ ✅ this 指向 Timer 实例
}, 1000);
}
}
在这个例子中,setInterval 的回调函数如果不是箭头函数,它的 this 会在调用时被设为全局对象(浏览器中是 window,Node.js 中是 global)。箭头函数自动捕获定义时的 this,所以你不用手动 bind 或者 const self = this。
TypeScript 中声明 this 类型
有时你需要在一个函数中明确告诉 TypeScript”这个函数的 this 应该是什么类型”。TypeScript 利用了 JavaScript 的一个语法空白:你不能给函数声明一个叫 this 的参数,所以 TypeScript 就把第一个名为 this 的参数当作 this 的类型声明。
interface User {
name: string;
isAdmin: boolean;
}
// this 参数声明 this 的类型
function becomeAdmin(this: User) {
this.isAdmin = true;
}
const user: User = { name: "Alice", isAdmin: false, becomeAdmin };
user.becomeAdmin(); // ✅ 调用上下文必须是 User 类型
注意 this: User 这个参数——它不占用实际参数位置,调用时也不需要传。它只是一个类型声明,告诉编译器”这个函数只有在 this 是 User 类型时才能被调用”。
这在回调风格的 API 中很有用:
interface DB {
filterUsers(filter: (this: User) => boolean): User[];
}
function getDB(): DB {
// 模拟实现
return {
filterUsers(filter) {
const allUsers: User[] = [
{ name: "Alice", isAdmin: false, becomeAdmin() {} },
{ name: "Bob", isAdmin: true, becomeAdmin() {} },
];
return allUsers.filter(filter);
},
};
}
const db = getDB();
// ✅ 用普通函数,this 类型会被检查
const admins = db.filterUsers(function (this: User) {
return this.isAdmin;
});
// ❌ 用箭头函数,this 来自外层
const nonAdmins = db.filterUsers(() => {
return this.isAdmin;
// ~~~~ 箭头函数捕获外层 this,不是 User 类型
});
这个例子中,filterUsers 的回调被声明为 (this: User) => boolean。如果你用普通函数并声明了 this: User,TypeScript 就能检查你对 this 属性的访问是否正确。如果你用箭头函数,this 来自定义时的作用域,跟 User 没关系。
noImplicitThis 选项
TypeScript 7.0 默认开启了 strict: true,这会自动启用 noImplicitThis。这个选项的意思是:如果函数中用了 this,但 TypeScript 推断不出 this 的类型,就报错。
// strict: true(7.0 默认),noImplicitThis 也默认开启
function showName() {
console.log(this.name);
// ~~~~ "this" 隐式具有类型 "any"
}
要修复这个错误,你需要声明 this 的类型:
function showName(this: { name: string }) {
console.log(this.name); // ✅
}
在对象方法和类方法中,TypeScript 通常能自动推断 this 的类型,不需要手动声明:
const obj = {
name: "TypeScript",
showName() {
console.log(this.name); // ✅ TS 自动推断 this 为 obj 的类型
},
};
class Person {
name = "TypeScript";
showName() {
console.log(this.name); // ✅ TS 自动推断 this 为 Person 实例
}
}
回调中的 this 问题与解决方案
回调函数中的 this 是最高频的坑。模式一般是:你把一个方法当作回调传出去,方法中用到了 this,但调用时 this 上下文丢了。
class Button {
label = "Click me";
// 普通方法
handleClickNormal() {
console.log(this.label);
// 当作为事件处理器传递时,this 不是 Button 实例
}
// 箭头函数属性
handleClickArrow = () => {
console.log(this.label);
// this 永远是 Button 实例
};
}
const btn = new Button();
// ❌ 普通方法作为回调——this 丢失
const handler1 = btn.handleClickNormal;
handler1(); // undefined(strict 模式下 this 是 undefined)
// ✅ 箭头函数属性作为回调——this 正确
const handler2 = btn.handleClickArrow;
handler2(); // "Click me"
两种方案各有代价:普通方法存在原型上,所有实例共享;箭头函数属性存在实例上,每个实例都会创建一份。如果实例数量很大,用箭头函数属性会增加内存开销。
Tip对于组件类、事件处理等场景,优先用箭头函数属性。对于普通工具类的方法,用普通方法即可——TypeScript 的
noImplicitThis会在你误用时提醒你。
何时用箭头函数
总结一下选择策略:
- 简单回调(
map、filter、forEach等)——箭头函数最简洁。 - 需要保持 this 上下文(事件处理、定时器回调)——箭头函数,或者箭头函数属性。
- 需要动态 this(比如一个方法会被不同对象调用,this 指向不同对象)——普通函数,配合
this: Type声明。 - 不需要用到 this——两者都可以,箭头函数通常更短。
// 不需要 this,箭头函数更短
[1, 2, 3].map((n) => n * 2);
// 需要动态 this,用普通函数
const calculator = {
value: 0,
add(this: { value: number }, n: number) {
this.value += n;
},
};
// 需要固定 this,用箭头函数属性
class Counter {
count = 0;
increment = () => {
this.count++;
};
}
小结
箭头函数不绑定自己的 this,它从定义时的作用域继承 this。在 TypeScript 中,你可以用 this: Type 作为第一个参数来声明 this 类型。noImplicitThis(7.0 默认开启)会在 this 类型不明确时报错。核心原则:回调中需要保持 this 上下文时用箭头函数,需要动态 this 时用普通函数。