首页 / TypeScript 入门教程 / 箭头函数与 this

TypeScript 入门教程

箭头函数与 this

本教程共 80 篇 · 第 20 篇 · 更新于 2026-08-10 · 约 10 分钟阅读

TypeScriptTypeScript 入门教程箭头函数this

本节目标:理解箭头函数与普通函数在 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 从箭头函数定义时的外层作用域继承。在模块顶层定义时,外层就是全局作用域(或者模块作用域),thisundefined(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 这个参数——它不占用实际参数位置,调用时也不需要传。它只是一个类型声明,告诉编译器”这个函数只有在 thisUser 类型时才能被调用”。

这在回调风格的 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 会在你误用时提醒你。

何时用箭头函数

总结一下选择策略:

  1. 简单回调mapfilterforEach 等)——箭头函数最简洁。
  2. 需要保持 this 上下文(事件处理、定时器回调)——箭头函数,或者箭头函数属性。
  3. 需要动态 this(比如一个方法会被不同对象调用,this 指向不同对象)——普通函数,配合 this: Type 声明。
  4. 不需要用到 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 时用普通函数。