Typescript中autoBind装饰器绑定函数this指向的运行原理是什么?
TypeScript autoBind 装饰器底层实现原理
1. 装饰器的触发时机
你编写的autoBind属于方法装饰器,触发时机是类声明阶段(而非类实例化阶段):
- TS 编译完成后,只要代码加载到
ProjectInput类的声明,就会立即执行autoBind函数,打印Calling Decorator日志 - 执行时会拿到三个参数:类的原型对象、修饰的方法名、该方法的属性描述符
2. 重写属性描述符的作用
你在装饰器中返回了新的属性描述符,将原来的普通方法属性,替换成了访问器属性(getter):
const adjustableDescriptor: PropertyDescriptor = { configurable : true, get(){ console.log("Calling get"); const boundFn = originalMethod.bind(this); return boundFn; } }
这个替换是整个绑定逻辑的核心:
- 访问器属性的
get函数的this,永远指向当前正在访问该属性的对象,也就是ProjectInput的实例 - 只要有代码访问实例的
submitHandler属性,就会自动触发get函数
3. this绑定的执行逻辑
当你在configure方法中执行this.element.addEventListener("submit",this.submitHandler)时:
- 访问
this.submitHandler触发get函数 get内部拿到的this就是当前ProjectInput的实例- 调用
originalMethod.bind(this)将原方法的this永久绑定到当前实例,返回绑定后的新函数 - 这个绑定后的函数被传给
addEventListener作为事件回调,后续事件触发时,回调的this永远指向ProjectInput实例,不会因为事件触发的上下文改变而丢失
可选优化点
你当前的实现每次访问submitHandler都会执行一次bind生成新函数,可以增加缓存逻辑避免重复绑定:
function autoBind( target:any, methodName:String, descriptor:PropertyDescriptor ){ console.log("Calling Decorator"); const originalMethod = descriptor.value; const adjustableDescriptor: PropertyDescriptor = { configurable : true, get(){ console.log("Calling get"); const boundFn = originalMethod.bind(this); // 绑定后直接重写该属性为绑定后的函数,下次访问直接走缓存,无需重复绑定 Object.defineProperty(this, methodName, { value: boundFn, configurable: true, writable: true }); return boundFn; } } return adjustableDescriptor; }
内容的提问来源于stack exchange,提问作者Abhay Jaiswal
相关产品推荐
相关产品推荐

