TypeScript异步执行器中this指向undefined问题排查求助
TypeScript类方法中this为undefined的问题解析
问题场景
编写的TypeScript代码如下:
class Executor { name: string; startDate: Date; endDate: Date; steps: { (): Promise<void> }[]; constructor(startDate: Date, endDate: Date) { this.name = 'chartNoteFaxing'; console.log(`Setting startDate ${startDate} and endDate: ${endDate}`); this.startDate = startDate; this.endDate = endDate; console.log(`this.startDate ${this.startDate} this.endDate: ${this.endDate}`); this.steps = [ this.sayHi, ]; } async sayHi() { console.log('GOT HERE???') console.log(`${this}`); console.log(`Hi! Got to here with ${this.name}`); } async execute() { for (const step of this.steps) { console.log('About to run step'); console.log(`${this}`); await step(); } } }
执行后输出:
[LOG]: "Setting startDate Mon Nov 28 2022 00:00:00 GMT-0500 (Eastern Standard Time) and endDate: Mon Nov 28 2022 19:00:00 GMT-0500 (Eastern Standard Time)" [LOG]: "this.startDate Mon Nov 28 2022 00:00:00 GMT-0500 (Eastern Standard Time) this.endDate: Mon Nov 28 2022 19:00:00 GMT-0500 (Eastern Standard Time)" [LOG]: "About to run step" [LOG]: "[object Object]" [LOG]: "GOT HERE???" [LOG]: "undefined"
可见sayHi方法内的this为undefined,但调用await step()前的this正常指向实例,疑惑类已实例化为何出现此异常。
原因剖析
这是JavaScript/TypeScript中函数绑定的典型问题:
- 当把
this.sayHi存入steps数组时,只是提取了该方法的函数引用,它与原实例的绑定关系被剥离。 - 单独执行
step()时,函数处于严格模式下的undefined上下文,因此this指向undefined。而execute方法内的this始终指向实例,所以调用step()前的日志显示正常。
修复方案
1. 构造函数内手动绑定this
在构造函数中通过bind方法把sayHi与实例绑定,确保无论如何调用,this都指向当前实例:
constructor(startDate: Date, endDate: Date) { this.name = 'chartNoteFaxing'; console.log(`Setting startDate ${startDate} and endDate: ${endDate}`); this.startDate = startDate; this.endDate = endDate; console.log(`this.startDate ${this.startDate} this.endDate: ${this.endDate}`); // 绑定this到实例 this.sayHi = this.sayHi.bind(this); this.steps = [ this.sayHi, ]; }
2. 使用箭头函数定义类方法
箭头函数会自动捕获当前上下文的this,永久指向实例,无需手动绑定:
// 改用箭头函数定义方法 async sayHi = () => { console.log('GOT HERE???') console.log(`${this}`); console.log(`Hi! Got to here with ${this.name}`); }
注意:这种方式会让每个实例都创建独立的函数副本,而非共享原型上的方法,适合小型类或对性能影响不大的场景。
3. 调用时手动传入this
在execute方法中执行step时,用call或apply把当前实例的this传递进去:
async execute() { for (const step of this.steps) { console.log('About to run step'); console.log(`${this}`); // 手动绑定当前实例的this await step.call(this); } }
内容的提问来源于stack exchange,提问作者jlarks32
相关产品推荐
相关产品推荐

